实现逆向工程——汇编指令演练

在上一章中,我们介绍了一些汇编语言指令。汇编语言中有多种类型的指令,这些指令可以通过分组来更清晰地了解特定指令集的功能和目的。为了理解在逆向工程中逐条分析基础汇编指令的意义,我们将举一个现实生活中的例子。

你小时候有没有拆过玩具?打开玩具,查看其内部组件总是很有趣。如今,如果你需要了解玩具的内部工作原理,首先要理解安装在玩具硬件设计中的各个组件。要揭示玩具的内部运行机制,就必须掌握其中每个组件的工作原理。整个过程在某种程度上类似于对玩具的逆向工程。

同理,要对任何软件或应用进行逆向工程,我们需要将其反汇编成不同的指令,并对这些反汇编得到的汇编指令进行理解。因此,要了解任何软件或应用的工作原理,就需要清晰掌握各条指令及其执行路径。这就要求我们理解汇编语言中不同类型的指令。

章节结构

本章将涵盖以下主题:

  • 不同的汇编语言指令
  • 汇编指令的语法
  • 汇编指令的分组

学习目标

通过本章学习,你将能够理解逆向工程中常用的重要汇编指令,并了解这些指令如何被分组以便于理解,还会结合示例加深印象。我们还将学习指令的语法、它们的内部工作原理,以及不同类型指令背后的基本概念。

不同的汇编语言指令

指令是汇编代码的基本构建块。指令由操作码(opcode)与零个或多个操作数(operand)组成。

操作码通常称为 opcode。操作数可以分为三种类型:

  • 立即数操作数(Immediate operands) :固定的十六进制数值,如 0x0A
  • 寄存器操作数(Register operands) :可以是任意寄存器,如 ECXEAX 等。
  • 内存地址操作数(Memory address operands) :表示内存地址,写在方括号内,如 [EAX]

程序代码以操作码(opcode)和操作数交替的形式按顺序存储在内存中,保存在连续的内存位置中。如下图所示:

  • 指令 1 占用两个内存位置,
  • 指令 2 也占用两个内存位置,
  • 指令 3 仅占用一个内存位置。

看看下面这个带有寄存器操作数的汇编指令示例:

指令格式:

复制代码
OPERATION_CODE  DESTINATION_OPERAND  SOURCE_OPERAND

示例:

复制代码
MOV EAX, ECX
  • OPERATION_CODE = MOV,表示"移动"
  • DESTINATION_OPERAND = EAX,目标寄存器
  • SOURCE_OPERAND = ECX,源寄存器

此指令将 ECX 寄存器中的数据移动到 EAX 寄存器。每条指令所对应的操作码(opcode)告诉 CPU 程序要执行何种操作。上述指令的操作码为 89 C8,这是其十六进制表示。反汇编器会将这些操作码转换成人类可读的汇编语句,因此 89 C8 会被译为 MOV EAX, ECX

既然我们已经掌握了汇编指令的概念,接下来要介绍在逆向工程中常见的主要汇编指令,并将它们按功能分组以便理解。大致可分为以下几类:

  • 栈操作指令
  • 数据传输指令
  • 算术指令
  • 程序执行指令
  • 分支指令
  • 位操作指令
  • 处理器控制指令
  • 字符串指令

下面我们将逐一查看每个类别,了解其中包含的汇编指令。

栈操作指令

这些是用于在栈上进行数据传输的通用指令。

PUSH

指令格式:

复制代码
PUSH SOURCE_OPERAND

含义:

将源操作数的值复制到栈顶,并将 ESP 寄存器减小相应字节数。
影响标志:

PUSHAD

指令格式:

复制代码
PUSHAD

含义:

按顺序将所有通用寄存器的值压入栈中,顺序为:EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI。
影响标志:

PUSHFD

指令格式:

复制代码
PUSHFD

含义:

将 EFLAGS(标志寄存器)的值压入栈中。
影响标志:

POP

指令格式:

复制代码
POP DESTINATION_OPERAND

含义:

从栈顶弹出一个值,并复制到目标操作数;然后将 ESP 寄存器增大相应字节数。
影响标志:

POPAD

指令格式:

复制代码
POPAD

含义:

按顺序从栈中弹出值并写入寄存器,顺序为:EDI、ESI、EBP、ESP(该值会被忽略)、EDX、ECX、EAX。
影响标志:

POPFD

指令格式:

复制代码
POPFD

含义:

从栈顶弹出一个双字(DWORD)并写入 EFLAGS(标志寄存器)。
影响标志:

RET

指令格式:

css 复制代码
RET [nBytes]

含义:

函数返回指令,将控制权从被调用者(callee)转移回调用者(caller)------即跳转到保存在栈上的返回地址。可选的 nBytes 表示在返回时额外清理栈上 n 字节的参数空间。
影响标志:

数据传输指令

这些是用于数据传输操作的通用指令。

MOV

指令格式:

复制代码
MOV 目标操作数, 源操作数

含义:

将源操作数中的数据复制到目标操作数中,并将结果存储在目标操作数。
影响标志:

LEA

指令格式:

复制代码
LEA 寄存器, 操作数

含义:

LEA(Load Effective Address)将操作数的有效地址加载到指定寄存器中。
影响标志:

XCHG

指令格式:

objectivec 复制代码
XCHG 目标操作数, 源操作数

含义:

交换源操作数和目标操作数中的值。
影响标志:

CMPXCHG

指令格式:

objectivec 复制代码
CMPXCHG 目标操作数, 源操作数

含义:

用于比较并交换。首先将 EAX 与目标操作数比较:

  • 如果 EAX == 目标操作数,则将源操作数的值加载到目标操作数。
  • 如果 EAX != 目标操作数,则将目标操作数的值加载到 EAX。
    影响标志: CF、ZF、SF、AF、PF、OF

LAHF

指令格式:

复制代码
LAHF

含义:

将标志寄存器的状态复制到 AH 寄存器中。仅将以下 5 位复制到 AH 的位 7、6、4、2 和 0;AH 的位 5、3 和 1 将保持不变。
执行此指令后,AH 寄存器的位状态:

影响标志:

SAHF

指令格式:

复制代码
SAHF

含义:

将 AH 寄存器的位(7、6、4、2、0)存入标志寄存器,对应更新 SF、ZF、AF、PF 和 CF。
影响标志: SF、ZF、AF、PF、CF

LAR

指令格式:

复制代码
LAR 目标操作数, 源操作数

含义:

从源操作数指定的段描述符中加载有效权限位到目标操作数。
影响标志: ZF

MOVSX

指令格式:

复制代码
MOVSX 目标操作数, 源操作数

含义:

带符号扩展移动:将源操作数复制到目标操作数,并用符号位(最高位)填充目标寄存器中多余的高位。
影响标志:

MOVZX

指令格式:

复制代码
MOVZX 目标操作数, 源操作数

含义:

带零扩展移动:将源操作数复制到目标操作数,并用 0 填充目标寄存器中多余的高位。
影响标志:

XLAT

指令格式:

复制代码
XLAT

含义:

表查找(Translate):以 AL 寄存器作为无符号索引,将 AL 设置为 DS:[EBX + AL]。其中 EBX 保存表的基地址。

MOVS

指令格式:

复制代码
MOVS 目标字符串, 源字符串

含义:

将数据(Byte、WORD、DWORD)从源字符串复制到目标字符串,其中:

  • 源字符串(SOURCE_STRING) 由 DS:SI(或 ESI)指向
  • 目标字符串(DESTINATION_STRING) 由 ES:DI(或 EDI)指向
  • SI 是数据段(DS)中的偏移地址
  • DI 是附加段(ES)中的偏移地址
    影响标志:

算术指令

以下指令用于汇编语言中的算术运算。

AAA

指令格式:

复制代码
AAA

含义:

ASCII 加法调整(ASCII Adjust after Addition)。用于对两个"未打包"BCD 数(ASCII 码 '0'--'9' 即 0x30--0x39)执行 ADD 后,将结果转换为两位 BCD。
影响标志: AF、CF;(SF、ZF、OF、PF 未定义)
示例:

ini 复制代码
XOR AH, AH        ; 清零 AH  
MOV AL, 32h       ; AL = ASCII '2'  
ADD AL, 39h       ; AL = 0x6B(ASCII 9 + ASCII 2 不是 ASCII)  
AAA               ; 调整后 AH = 0x01, AL = 0x01,AX = 0x0101  

AAS

指令格式:

复制代码
AAS

含义:

ASCII 减法调整(ASCII Adjust after Subtraction)。用于对两个"未打包"BCD 数执行 SUB 后,将结果转换为两位 BCD。
影响标志: AF、CF;(SF、ZF、OF、PF 未定义)

AAD

指令格式:

复制代码
AAD

含义:

ASCII 除法调整(ASCII Adjust before Division)。用于在 DIV 之前,将 AH:AL 中的"未打包"BCD 数转换为二进制,商放入 AL,余数放入 AH,均为"未打包"BCD。
影响标志: PF、SF、ZF
示例(68 ÷ 8):

ini 复制代码
MOV AX, 0608h    ; AH=0x06, AL=0x08  
MOV CH, 08h      ; 除数 ASCII '8'  
AAD              ; AX = 0044h (BCD 44,即十进制 68)  
DIV CH           ; AL = 08 (商), AH = 04 (余)  

AAM

指令格式:

复制代码
AAM

含义:

ASCII 乘法调整(ASCII Adjust after Multiplication)。用于对两个"未打包"BCD 数执行 MUL 后,将结果(存于 AX)拆分为 AH, AL 两个"未打包"BCD。
影响标志: PF、SF、ZF
示例(7 × 5):

ini 复制代码
MOV AL, 07h      ; AL = 0x07  
MOV BH, 05h      ; BH = 0x05  
MUL BH           ; AX = 0x0023 (十进制 35)  
AAM              ; AX = 0203h (AH=02, AL=03)  

ADC

指令格式:

复制代码
ADC 目标, 源

含义:

带进位加法。计算 目标 + 源 + CF,结果存回目标。
影响标志: AF、CF、OF、PF、SF、ZF

ADD

指令格式:

sql 复制代码
ADD 目标, 源

含义:

加法。计算 目标 + 源,结果存回目标。
影响标志: AF、CF、OF、PF、SF、ZF

CMP

指令格式:

objectivec 复制代码
CMP 目标, 源

含义:

比较。执行 目标 -- 源,但不保存结果,仅更新标志以供后续分支等指令使用。
影响标志: AF、CF、OF、PF、SF、ZF

DAA

指令格式:

复制代码
DAA

含义:

BCD 加法调整(Decimal Adjust after Addition)。在对 AL 执行 ADD/ADC 后,用于将结果调整为 BCD 形式,仅作用于 AL。
影响标志: AF、CF;(OF、PF、SF、ZF 未定义)
示例:

ini 复制代码
MOV DX, 1122h    ; 加载 BCD 1122  
MOV BX, 3088h    ; 加载 BCD 3088  
MOV AL, BL       ; 将低字节 88h 装入 AL  
ADD AL, DL       ; 执行 AL + DL  
DAA              ; BCD 调整后的结果存回 AL  

DAS

指令格式:

复制代码
DAS

含义:

BCD 减法调整(Decimal Adjust after Subtraction)。在对 AL 执行 SUB/SBB 后,用于将结果调整为 BCD 形式,仅作用于 AL。
影响标志: AF、CF;(OF、PF、SF、ZF 未定义)
示例:

css 复制代码
MOV DX, 1122h  
MOV BX, 3088h  
MOV AL, BL  
SUB AL, DL  
DAS              ; BCD 调整后的结果存回 AL  

DEC

指令格式:

sql 复制代码
DEC 目标

含义:

目标减 1,结果存回目标(寄存器或内存)。
影响标志: AF、OF、PF、SF、ZF
示例:

ini 复制代码
MOV EAX, 02h  
DEC EAX          ; EAX = 01h  

DIV

指令格式:

css 复制代码
DIV 源

含义:

无符号除法:将 AX、DX:AX 或 EDX:EAX 作为被除数,分别按 BYTE、WORD、DWORD 大小除以源操作数(BYTE/WORD/DWORD)。

  • BYTE ÷ BYTE:被除数在 AL,结果商放 AL,余数放 AH。
  • WORD ÷ WORD:被除数在 DX:AX(高 WORD 在 DX,低 WORD 在 AX),商放 AX,余数放 DX。
  • DWORD ÷ DWORD:被除数在 EDX:EAX(高 DWORD 在 EDX,低 DWORD 在 EAX),商放 EAX,余数放 EDX。
    影响标志:
    示例:
css 复制代码
MOV DX, 0  
MOV AX, 8003h  
MOV CX, 0100h  
DIV CX          ; AX = 0080h, DX = 0003h  

IDIV

指令格式:

复制代码
IDIV 源

含义:

有符号除法;与 DIV 相同,但对被除数和商、余数进行有符号处理。
影响标志:

MUL

指令格式:

复制代码
MUL 源

含义:

无符号乘法:将 AL、AX 或 EAX(被乘数)与源操作数(BYTE/WORD/DWORD)相乘,结果存于 AX、DX:AX 或 EDX:EAX。

  • BYTE × BYTE:AL × 源 → AX(高 8 位 AH,低 8 位 AL)。
  • WORD × WORD:AX × 源 → DX:AX(高 WORD 在 DX,低 WORD 在 AX)。
  • DWORD × DWORD:EAX × 源 → EDX:EAX(高 DWORD 在 EDX,低 DWORD 在 EAX)。
    影响标志: OF、CF
    示例:
ini 复制代码
MOV AX, 8003h  
MOV CX, 0100h  
MUL CX          ; AX = 0300h, DX = 0080h  

IMUL

指令格式:

复制代码
IMUL 源

含义:

有符号乘法;用有符号规则进行乘法运算,其余与 MUL 相同。
影响标志: OF、CF

INC

指令格式:

复制代码
INC 目标

含义:

目标加 1,结果存回目标(寄存器或内存)。
影响标志: AF、OF、PF、SF、ZF
示例:

ini 复制代码
MOV EAX, 02h  
INC EAX         ; EAX = 03h  

NEG

指令格式:

复制代码
NEG 目标

含义:

取目标的二进制补码(符号取反):执行 0 -- 目标,然后采用二补码保存结果。
影响标志: AF、OF、PF、SF、ZF
示例:

ini 复制代码
MOV EAX, 02h  
NEG EAX         ; EAX = FFFFFFFEh (-2)  

SBB

指令格式:

复制代码
SBB 目标, 源

含义:

带借位减法:计算 目标 -- 源 -- CF,结果存回目标。
影响标志: AF、CF、OF、PF、SF、ZF

SUB

指令格式:

vbnet 复制代码
SUB 目标, 源

含义:

减法:计算 目标 -- 源,结果存回目标。
影响标志: AF、CF、OF、PF、SF、ZF

XADD

指令格式:

复制代码
XADD 目标, 源

含义:

先执行加法(如 ADD),将结果存入目标;然后将原目标值复制回源。
影响标志: AF、CF、OF、PF、SF、ZF
示例:

ini 复制代码
MOV EAX, 00000001h  
MOV EBX, 00000002h  
XADD EAX, EBX   ; EAX = 00000003h, EBX = 00000001h  

程序执行指令

这些指令用于控制程序执行流程及标志的更新。

CALL

指令格式:

objectivec 复制代码
CALL 目标操作数

含义:

在程序执行中,当一个函数调用另一个函数时使用 CALL。执行时,指令指针跳转到被调用过程(callee)的代码。CPU 会将 CALL 指令后下一条指令的地址压入栈中,作为返回地址;被调用过程执行完毕后,通过 RET 指令弹出该地址,返回到调用者(caller)继续执行。
影响标志:
示例:

ini 复制代码
CALL PROC_LABEL    ; 跳转到标号 PROC_LABEL 所在的过程  

ENTER

指令格式:

复制代码
ENTER 存储字节数, 嵌套级别

含义:

用于创建过程栈帧,分配存储空间并处理嵌套级别。适用于支持块结构语言(如 C、Pascal)的过程调用。

  • 存储字节数:在栈上预留的字节数。
  • 嵌套级别 :从 0 到 31,表示过程调用的嵌套深度。
    影响标志:

LEAVE

指令格式:

复制代码
LEAVE

含义:

用于释放由 ENTER 创建的过程栈帧,恢复 (E)SP/(E)BP,准备 RET 返回。
影响标志:

INT

指令格式:

sql 复制代码
INT <类型>

含义:

软件中断指令,显式触发中断处理。<类型> 为 0--255 的中断号。执行时:

  1. 将 FLAGS 寄存器压栈;
  2. 将 CS(代码段寄存器)压栈;
  3. INT 指令后下一条指令的偏移地址压栈;
  4. 类型 × 4 的内存地址处读取新的 IP(指令指针)并加载;
  5. (类型 × 4) + 2 处读取新的 CS;
  6. 清除 TF(陷阱标志)和 IF(中断标志);
    跳转到中断服务例程(ISR)执行。
    影响标志: IF、TF

INTO

指令格式:

sql 复制代码
INTO

含义:

溢出中断(Interrupt on Overflow):若 OF(溢出标志)置位,则行为同 INT 4,触发中断;否则继续顺序执行。流程与 INT 类似:

  1. 压栈 FLAGS、CS、返回地址;
  2. 4 × 4 处读取新 IP;
  3. 4 × 4 + 2 处读取新 CS;
  4. 清除 IF、TF。
    影响标志: IF、TF

IRET

指令格式:

复制代码
IRET

含义:

中断返回(Interrupt Return):结束中断服务例程,将栈上的 IP、CS 和 FLAGS 依次弹出,恢复到中断前的执行状态,继续被中断的程序。
影响标志: AF、CF、DF、IF、ZF、SF、TF、PF

LOOP

指令格式:

vbnet 复制代码
LOOP 目标

含义:

将 (E)CX 寄存器减 1;若新值非零,则跳转到指定目标;否则顺序执行下一条指令。
影响标志:
示例:

ini 复制代码
LOOP MEM_LOC    ; ECX 减 1 后若非零,则跳转到 MEM_LOC  

LOOPE / LOOPZ

指令格式:

ini 复制代码
LOOPE 目标    ; 或 LOOPZ 目标

含义:

将 (E)CX 减 1;若新值非零且 ZF=1,则跳转到目标;否则继续执行下一条。
影响标志:

LOOPNE / LOOPNZ

指令格式:

ini 复制代码
LOOPNE 目标    ; 或 LOOPNZ 目标

含义:

将 (E)CX 减 1;若新值非零且 ZF=0,则跳转到目标;否则继续执行下一条。
影响标志:

TEST

指令格式:

复制代码
TEST 目标操作数, 源操作数

含义:

对目标和源执行按位 AND 操作,但不保存结果,仅更新 SF、ZF、PF 标志。常用于检查寄存器或内存是否为零,而不修改其值。
影响标志: SF、ZF、PF
示例:

ini 复制代码
TEST EAX, 01h   ; 若 EAX=01h,则 ZF=0  
TEST EAX, 02h   ; 若 EAX=01h,则 ZF=1  
TEST EAX, EAX   ; 检查 EAX 是否为零  

分支指令

分支指令用于控制代码执行的流程。x86 中有两类跳转:

  • 无条件跳转(Unconditional jump) :指令指针直接跳转到指定位置。

  • 条件跳转(Conditional jump) :在评估某个条件后,若满足则跳转,否则继续顺序执行。常配合下列两条指令设置标志:

    • TEST:按位与,不保存结果,仅影响标志。
    • CMP:相减,不保存结果,仅影响标志。

说明 :分支指令中的 DESTINATION_OPERAND 通常也称为标签(LABEL)或目标地址(DESTINATION ADDRESS),可以是相对于当前指令的位移,也可以是绝对地址。

JMP

复制代码
JMP 目标

含义 :无条件跳转到指定目标。
影响标志 :无
示例

ini 复制代码
JMP PROC_LABEL    ; 跳转到 PROC_LABEL  

JZ / JE

ini 复制代码
JZ  目标    ; 等同 JE

含义 :若 ZF=1(零标志置位),则跳转;否则继续执行下一条指令。
影响标志 :无
示例

ini 复制代码
JZ MEM_LOC       ; 若 ZF=1,则跳转  

JNZ / JNE

ini 复制代码
JNZ 目标    ; 等同 JNE

含义 :若 ZF=0(零标志清零),则跳转;否则顺序执行。
示例

ini 复制代码
JNZ MEM_LOC      ; 若 ZF=0,则跳转  

JG / JA

ini 复制代码
JG  目标    ; 有符号大于  
JA  目标    ; 无符号以上(等同 JG 对应无符号)

含义 :常配合 CMP 后使用。

  • JG(Jump if Greater):若有符号比较结果"目标 > 源",则跳转。
  • JA (Jump if Above):若无符号比较结果"目标 > 源",则跳转。
    示例
ini 复制代码
CMP EAX, 02h  
JG  MEM_LO      ; 若 EAX(有符号)> 2,跳转  
JA  MEM_LO      ; 若 EAX(无符号)> 2,跳转  

JGE / JAE

ini 复制代码
JGE 目标    ; 有符号 ≥  
JAE 目标    ; 无符号 ≥

含义

  • JGE:若有符号"目标 ≥ 源",跳转。
  • JAE :若无符号"目标 ≥ 源",跳转。
    示例
ini 复制代码
CMP EAX, 02h  
JGE MEM_LO      ; 若 EAX ≥ 2,跳转  
JAE MEM_LO      ; 若 EAX(无符号)≥ 2,跳转  

JL / JB

ini 复制代码
JL  目标    ; 有符号 <  
JB  目标    ; 无符号 <(等同 JL 对应无符号)

含义

  • JL:若有符号"目标 < 源",跳转。
  • JB :若无符号"目标 < 源",跳转。
    示例
ini 复制代码
CMP EAX, 02h  
JL  MEM_LO      ; 若 EAX < 2,跳转  
JB  MEM_LO      ; 若 EAX(无符号)< 4,跳转  

JLE / JBE

ini 复制代码
JLE 目标    ; 有符号 ≤  
JBE 目标    ; 无符号 ≤

含义

  • JLE:若有符号"目标 ≤ 源",跳转。
  • JBE :若无符号"目标 ≤ 源",跳转。
    示例
ini 复制代码
CMP EAX, 02h  
JLE MEM_LO      ; 若 EAX ≤ 2,跳转  
JBE MEM_LO      ; 若 EAX(无符号)≤ 4,跳转  

JO

复制代码
JO  目标

含义 :若 OF=1(溢出标志置位),则跳转;否则继续。
示例

ini 复制代码
ADD AL, BL  
JO  MEM_LOC    ; 若加法溢出,跳转  

JS

复制代码
JS  目标

含义 :若 SF=1(符号标志置位),则跳转;否则继续。
示例

ini 复制代码
ADD AL, BL  
JS  MEM_LOC    ; 若结果为负,跳转  

JECXZ

复制代码
JECXZ 目标

含义 :若 ECX=0,则跳转;否则继续。
示例

ini 复制代码
JECXZ MEM_LOC  ; 若 ECX=0,跳转  

位操作指令

以下指令用于位级操作。在介绍这些指令之前,我们先回顾一下真值表:

BSWAP

指令格式:

复制代码
BSWAP 寄存器32

含义:

将寄存器中的字节顺序在大端与小端之间互换。
影响标志:
示例:

ini 复制代码
MOV EAX, 87654321h   ; EAX = 0x87654321  
BSWAP EAX            ; EAX = 0x21436587  

AND

指令格式:

复制代码
AND 目标操作数, 源操作数

含义:

对目标操作数和源操作数执行按位与运算,结果存回目标操作数。
影响标志: CF、OF、PF、SF、ZF
示例:

ini 复制代码
MOV EAX, 87654321h   ; EAX = 0x87654321  
MOV EBX, 21436587h   ; EBX = 0x21436587  
AND EAX, EBX         ; EAX = 0x01414101  

NOT

指令格式:

复制代码
NOT 目标操作数

含义:

对目标操作数执行按位取反(取一补码),所有 1 变为 0,所有 0 变为 1。
影响标志:
示例:

ini 复制代码
MOV EAX, 12121212h   ; EAX = 0x12121212  
NOT EAX              ; EAX = 0xEDEDEDED  

OR

指令格式:

复制代码
OR 目标操作数, 源操作数

含义:

对目标操作数和源操作数执行按位或运算,结果存回目标操作数。
影响标志: CF、OF、PF、SF、ZF
示例:

ini 复制代码
MOV EAX, 87654321h   ; EAX = 0x87654321  
MOV EBX, 21436587h   ; EBX = 0x21436587  
OR  EAX, EBX         ; EAX = 0xA76767A7  

XOR

指令格式:

vbnet 复制代码
XOR 目标操作数, 源操作数

含义:

对目标操作数和源操作数执行按位异或运算,结果存回目标操作数。
影响标志: CF、OF、PF、SF、ZF
示例:

ini 复制代码
MOV EAX, 87654321h   ; EAX = 0x87654321  
XOR EAX, EAX         ; EAX = 0x00000000  

RCL

指令格式:

复制代码
RCL 目标操作数, 计数

含义:

通过进位左循环移位(RCL)

RCL 指令通过 CF 标志将目标操作数中的位从右到左循环移动 n 次。每次循环时,最高有效位(MSB)移入 CF 标志,而原 CF 标志则进入最低有效位(LSB)。

  • 影响标志:CF、OF

  • 示例

    ini 复制代码
    MOV EAX, 01H    ; EAX = 00000001H, CF = 0
    RCL EAX, 2      ; 对 EAX 执行两次循环左移,结果 EAX = 0x00000004

通过进位右循环移位(RCR)

复制代码
RCR 目标操作数, 计数

含义:

RCR 指令通过 CF 标志将目标操作数中的位从左到右循环移动指定次数。每次循环时,最低有效位(LSB)移入 CF 标志,而原 CF 标志则进入最高有效位(MSB)。
影响标志: CF、OF

通过进位右循环移位(RCR)

RCR 指令通过 CF 标志将目标操作数中的位从左向右循环移动指定次数。每次循环时,最低有效位(LSB)移入 CF 标志,而原 CF 标志则进入最高有效位(MSB)。

  • 影响标志:CF、OF

  • 示例

    ini 复制代码
    MOV EAX, 01H    ; EAX = 00000001H,CF = 0  
    RCR EAX, 2      ; 对 EAX 执行两次通过进位右循环移位,结果 EAX = 0x80000000  

循环左移(ROL)

复制代码
ROL 目标操作数, 计数

含义:

循环左移(ROL)

ROL 指令将目标操作数中的位从右向左循环移动指定次数(n 次),最后一次移出的位值会存入 CF 标志。

  • 影响标志:CF、OF

  • 示例

    ini 复制代码
    MOV EAX, 40000001h    ; EAX = 0x40000001, CF = 0  
    ROL EAX, 2            ; 循环左移 2 位后,EAX = 0x00000005,CF = 1  

循环右移(ROR)

复制代码
ROR 目标操作数, 计数

含义:

将目标操作数中的位从左向右循环移动指定次数(n 次),最后一次移出的位值会存入 CF 标志。

  • 影响标志:CF、OF

循环右移(ROR)

ROR 指令将目标操作数中的位从左向右循环移动指定次数(n 次),最后一次移出的位值会存入 CF 标志。

  • 影响标志:CF、OF

  • 示例

    ini 复制代码
    MOV EAX, 40000001h    ; EAX = 0x40000001, CF = 1  
    ROR EAX, 2            ; 循环右移 2 位后,EAX = 0x50000000, CF = 0  

逻辑右移(SHR)

复制代码
SHR 目标操作数, 计数

含义:

逻辑右移指令将目标操作数的位向右移动指定次数(n 次),高位填充零,最低位移出的位存入 CF 标志。

  • 影响标志:CF、ZF、SF、PF

  • 示例

    ini 复制代码
    MOV EAX, 80000000h   ; EAX = 0x80000000  
    SHR EAX, 1           ; 逻辑右移 1 位后,EAX = 0x40000000, CF = 0  

逻辑右移(SHR)

SHR 指令将目标操作数的位从左向右逻辑移动指定次数(n 次),每次移出的最低位存入 CF 标志;由于是逻辑右移,最高位总是补零。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

  • 示例:

    ini 复制代码
    MOV EAX, 40000001h   ; EAX = 0x40000001, CF = 0  
    SHR EAX, 2           ; 逻辑右移 2 位后,EAX = 0x10000000, CF = 0  

逻辑左移(SHL)

复制代码
SHL 目标操作数, 计数

含义:

逻辑左移指令将目标操作数的位从右向左逻辑移动指定次数(n 次),每次移出的最高位存入 CF 标志;最低位总是补零。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

  • 示例:

    ini 复制代码
    MOV EAX, 00000001h   ; EAX = 0x00000001, CF = 0  
    SHL EAX, 2           ; 逻辑左移 2 位后,EAX = 0x00000004, CF = 0  

附注: 有关位移操作的详细说明,请参见附录中的"位移"部分。

逻辑左移(SHL)

SHL 指令将目标操作数的位从右向左逻辑移动指定次数(n 次),每次移出的最高位存入 CF 标志;由于是逻辑移位,最低位总是补零。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

  • 示例:

    ini 复制代码
    MOV EAX, 40000001h   ; EAX = 0x40000001, CF = 0  
    SHL EAX, 2           ; 逻辑左移 2 位后,EAX = 0x00000004, CF = 1  

算术右移(SAR)

复制代码
SAR 目标操作数, 计数

含义:

算术右移指令将目标操作数的位从左向右移动指定次数(n 次),最低位移出后存入 CF 标志;最高位按原符号位(MSB)填充,以保持有符号数的正负意义。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

  • 示例:

    ini 复制代码
    MOV EAX, 80000004h   ; EAX = 0x80000004, CF = 0  
    SAR EAX, 2           ; 算术右移 2 位后,EAX = 0xE0000001, CF = 0  

算术右移(SAR)将目标操作数的位从左向右移动指定次数(n 次),每次移出的最低位存入 CF 标志;由于是算术移位,最高位由原 MSB(符号位)决定。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

  • 示例:

    ini 复制代码
    MOV EAX, 40000001h   ; EAX = 0x40000001, CF = 1  
    SAR EAX, 2           ; 算术右移 2 位后,EAX = 0x10000000, CF = 0  

算术左移(SAL)

复制代码
SAL 目标操作数, 计数

含义:

SAL 即算术左移,其行为与逻辑左移(SHL)相同:将位从右向左移动指定次数,移出的最高位存入 CF,最低位补零。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

算术左移(SAL)将目标操作数的位从右向左移动指定次数(n 次),每次移出的最高位存入 CF 标志;由于是算术移位,最低位始终补零。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

  • 示例:

    ini 复制代码
    MOV EAX, 40000001h   ; EAX = 0x40000001, CF = 0  
    SAL EAX, 2           ; 算术左移 2 位后,EAX = 0x00000004, CF = 1  

双操作数逻辑左移(SHLD)

复制代码
SHLD 目标操作数, 源操作数, 计数

含义:

将目标操作数和源操作数组合视为一个较长的双操作数结构,然后对该结构执行逻辑左移。移动时,从目标操作数的右端填入源操作数的高位,最后移出的位存入 CF 标志;左移时,在最低位补零。常用于跨寄存器的位字段操作。

双操作数逻辑左移(SHLD)将目标操作数的位从右向左移动指定次数(n 次),目标操作数中留下的空位由源操作数中移出的高位填充;最后一次从目标操作数中移出的位存入 CF 标志。源操作数本身不会被修改。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

  • 示例:

    ini 复制代码
    MOV EAX, 40000001h   ; EAX = 0x40000001,CF = 0  
    MOV EBX, 50000001h   ; EBX = 0x50000001,CF = 0  
    SHLD EAX, EBX, 2     ; EAX = 0x00000005(原 EAX 左移两位)  
                         ; 再填入 EBX 的高两位:EAX = 0x50000001  
                         ; CF = 1(最后从 EAX 移出的位)  

双操作数逻辑右移(SHRD)

复制代码
SHRD 目标操作数, 源操作数, 计数

含义:

将目标操作数的位从左向右逻辑移动指定次数(n 次),目标操作数中留下的空位由源操作数中移出的低位填充;最后一次从目标操作数中移出的位存入 CF 标志。源操作数本身不会被修改。

双操作数逻辑右移(SHRD)

SHRD 将目标操作数的位从左向右逻辑移动指定次数(n 次),目标操作数中留下的空位由源操作数中移出的低位填充;最后一次从目标操作数中移出的位存入 CF 标志。源操作数本身不受影响。

  • 影响标志: CF、OF、PF、SF、ZF(AF 未定义)

  • 示例:

    ini 复制代码
    MOV EAX, 40000001h   ; EAX = 0x40000001,CF = 1  
    MOV EBX, 50000001h   ; EBX = 0x50000001,CF = 1  
    SHRD EAX, EBX, 2     ; EAX = 0x50000000(右移两位后填入 EBX 低位)  
                         ; 最终 EAX = 0x50000001,CF = 0  

处理器控制指令

以下指令用于控制处理器的运行状态。

CLC

objectivec 复制代码
CLC

Clear Carry Flag(清除进位标志) :将 CF 置 0。

  • 影响标志: CF

  • 示例:

    ini 复制代码
    MOV EAX, 40000001h   ; CF = 0  
    SAL EAX, 2           ; 执行 SAL 后 CF = 1  
    CLC                  ; 清除 CF,CF = 0  

CLD

objectivec 复制代码
CLD

Clear Direction Flag(清除方向标志) :将 DF 置 0。

  • 影响标志: DF

CLI

objectivec 复制代码
CLI

Clear Interrupt Flag(清除中断标志) :将 IF 置 0,使处理器不响应外部中断。

  • 影响标志: IF

CMC

objectivec 复制代码
CMC

Complement Carry(翻转进位标志) :将 CF 取反。

  • 影响标志: CF

  • 示例:

    ini 复制代码
    MOV EAX, 40000001h  
    SAL EAX, 2           ; CF = 1  
    CMC                  ; CF = 0  

ESC

复制代码
ESC 操作码, 源操作数

Escape to Coprocessor(协处理器转义) :将后跟的浮点或数学协处理器指令传递给协处理器执行。CPU 取指令字节并通过数据总线排入协处理器指令队列,直到 ESC 指令触发协处理器解码并执行对应操作。

  • 影响标志:

LOCK

makefile 复制代码
LOCK: 指令

LOCK 前缀:在指令前加上 LOCK 时,会拉高处理器的 LOCK 引脚,锁定系统总线。外部总线主控和外围设备在该指令执行完毕前无法使用总线,用于保证多核/多处理环境下关键指令的原子性。

  • 影响标志:

  • 示例:

    css 复制代码
    LOCK: MOV EAX, EBX  ; 在 MOV 执行期间锁定总线  

NOP

复制代码
NOP

No Operation(无操作) :不执行任何功能,仅占用指令周期。

  • 影响标志:

  • 示例:

    ini 复制代码
    NOP  ; 什么也不做  

STC

复制代码
STC

Set Carry Flag(置位进位标志) :将 CF 置 1。

  • 影响标志: CF

  • 示例:

    ini 复制代码
    CLC  ; CF = 0  
    STC  ; CF = 1  

STD

复制代码
STD

Set Direction Flag(置位方向标志) :将 DF 置 1。

  • 影响标志: DF

STI

复制代码
STI

Set Interrupt Flag(置位中断标志) :将 IF 置 1,使处理器响应中断请求。恢复系统对中断的处理能力。

  • 影响标志: IF

字符串操作指令

以下指令用于处理字符串操作。

CMPS / CMPSB / CMPSW / CMPSD

指令格式:

  • CMPSB 源字符串, 目标字符串
  • CMPSW 源字符串, 目标字符串
  • CMPSD 源字符串, 目标字符串

(CMPS = Compare + String;B = Byte,W = Word,D = DWORD)

含义:

用于比较两段字符串。源字符串由 ESI 指向,目标字符串由 EDI 指向。

  • CMPSB :按字节(byte)比较,等同于 CMP BYTE PTR [ESI], [EDI]
  • CMPSW:按字(word)比较;
  • CMPSD:按双字(dword)比较。

比较操作即执行 ESI/EDI 指向的字节、字或双字的相减,与 CMP 指令行为一致。

CMPS 指令常与前缀 REPE /REPZ(重复执行直到 ECX=0 或 ZF=0)一起使用。

  • 当 DF=0(方向标志清零)时,每次比较后 ESI 和 EDI 分别递增:B → +1,W → +2,D → +4;
  • 当 DF=1(方向标志置位)时,每次比较后 ESI 和 EDI 分别递减:B → --1,W → --2,D → --4。

影响标志: AF、CF、OF、PF、SF、ZF

示例:

ini 复制代码
MOV ECX, Length     ; 要比较的元素数量  
CLD                  ; DF=0,向前比较  
REPE CMPSB          ; 重复比较 ECX 次或直到不等  

上述代码按字节比较 [ESI][EDI],直到 ECX 归零或发现不相等处。

字符串操作指令

以下指令用于处理字符串及块输入输出操作。

CMPS/CMPSB/CMPSW/CMPSD

指令格式:

  • CMPSB
  • CMPSW
  • CMPSD

(CMPS = Compare + String;B = Byte,W = Word,D = DWORD)

含义:

比较由 ESI 指向的源字符串与由 EDI 指向的目标字符串:

  • CMPSB 按字节比较;
  • CMPSW 按字(2 字节)比较;
  • CMPSD 按双字(4 字节)比较。

每次比较即执行 CMP [ESI], [EDI](相减但不存结果,仅更新标志)。通常与前缀 REPE/REPZ(重复直至 ECX=0 或 ZF=0)配合使用。

  • DF=0 时,比较后 ESI、EDI 分别 +1/ +2/ +4;
  • DF=1 时,比较后 ESI、EDI 分别 --1/ --2/ --4。

影响标志: AF、CF、OF、PF、SF、ZF

示例:

ini 复制代码
MOV ESI, 0x41000001   ; ESI 指向 STRING1  
MOV EDI, 0x82000001   ; EDI 指向 STRING2  
MOV ECX, 0x08         ; 比较长度 8  
CLD                   ; DF=0,向前比较  
REPE CMPSB            ; 重复按字节比较,直至 ECX=0 或 ZF=0  

IN/INSB/INSW/INSD

含义:

将外设 I/O 端口的数据读入内存或寄存器。

  1. 寄存器输入

    复制代码
    IN  目的寄存器, 端口地址
    • 端口地址在立即数中指定;
    • 目的寄存器可为 AL/AX/EAX,决定读取 1/2/4 字节。
      示例:
    ini 复制代码
    IN EAX, 0x80     ; 从端口 0x80 读取双字到 EAX  
    IN AX,  0x80     ; 从端口 0x80 读取字到 AX  
  2. 块(字符串)输入

    复制代码
    INSB
    INSW
    INSD
    • 端口地址由 DX 指定,内存目标由 EDI 指向;
    • INSB 每次传输 1 字节,INSW 2 字节,INSD 4 字节;
    • 通常与前缀 REP(重复至 ECX=0)一起使用;
    • DF=0 时 EDI += 1/2/4,DF=1 时 EDI -= 1/2/4。

影响标志:

示例:

css 复制代码
MOV DX, PORT_ADDRESS  
MOV EDI, offset STR  
INSW                  ; 从端口 DX 读一个字到 [EDI]  

OUT/OUTSB/OUTSW/OUTSD

含义:

将内存或寄存器的数据输出到外设 I/O 端口。

  1. 寄存器输出

    sql 复制代码
    OUT  端口地址, 源寄存器
    • 源寄存器 AL/AX/EAX 决定输出 1/2/4 字节;
      示例:
    ini 复制代码
    OUT 0x80, EAX    ; 将 EAX 的双字输出到端口 0x80  
    OUT 0x80, AX     ; 将 AX 的字输出到端口 0x80  
  2. 块(字符串)输出

    复制代码
    OUTSB
    OUTSW
    OUTSD
    • 端口地址由 DX 指定,数据源由 ESI 指向;
    • OUTSB 每次传输 1 字节,OUTSW 2 字节,OUTSD 4 字节;
    • 通常与前缀 REP 一起使用;
    • DF=0 时 ESI += 1/2/4,DF=1 时 ESI -= 1/2/4。

影响标志:

示例:

css 复制代码
MOV ESI, offset STR  
MOV DX, PORT_ADDRESS  
OUTSW                ; 将 [ESI] 的一个字输出到端口 DX  

LODS/LODSB/LODSW/LODSD

指令格式:

复制代码
LODSB
LODSW
LODSD

含义:

从内存加载字符串到寄存器:

  • LODSB → AL ← [ESI];
  • LODSW → AX ← [ESI];
  • LODSD → EAX ← [ESI];
  • DF=0 时 ESI += 1/2/4,DF=1 时 ESI -= 1/2/4。

影响标志:

示例:

css 复制代码
CLD  
MOV ESI, offset STR  
LODSB ; AL = [ESI]  

STOS/STOSB/STOSW/STOSD

指令格式:

复制代码
STOSB
STOSW
STOSD

含义:

将寄存器中的字符串数据存到内存:

  • STOSB → [EDI] ← AL;
  • STOSW → [EDI] ← AX;
  • STOSD → [EDI] ← EAX;
  • DF=0 时 EDI += 1/2/4,DF=1 时 EDI -= 1/2/4。

影响标志:

示例:

css 复制代码
CLD  
MOV EDI, offset STR  
STOSB ; [EDI] = AL  

SCAS/SCASB/SCASW/SCASD

指令格式:

复制代码
SCASB
SCASW
SCASD

含义:

扫描内存并与寄存器比较:

  • SCASB → 比较 AL 与 [EDI];
  • SCASW → 比较 AX 与 [EDI];
  • SCASD → 比较 EAX 与 [EDI];
  • 结果不存储,仅更新标志;
  • DF=0 时 EDI += 1/2/4,DF=1 时 EDI -= 1/2/4。

影响标志:

示例:

ini 复制代码
MOV ECX, 100  
MOV EDI, offset STR  
MOV AL, 0x20      ; 查找空格  
REPNE SCASB       ; 重复直至 ECX=0 或 ZF=1  

MOVS/MOVSB/MOVSW/MOVSD

指令格式:

复制代码
MOVSB
MOVSW
MOVSD

含义:

从 [ESI] 复制字符串到 [EDI]:

  • MOVSB → 1 字节,
  • MOVSW → 2 字节,
  • MOVSD → 4 字节,
  • DF=0 时 ESI/EDI += 1/2/4,DF=1 时 ESI/EDI -= 1/2/4。

影响标志:

示例:

ini 复制代码
MOV ESI, SRC_STR  
MOV EDI, DST_STR  
MOV ECX, 5  
CLD  
REP MOVSB         ; 复制 5 字节  

REP/REPE/REPZ/REPNE/REPNZ

  • REP + 字符串指令:重复执行,直至 ECX=0。
  • REPE/REPZ:重复执行,直至 ECX=0 或 ZF=0。
  • REPNE/REPNZ:重复执行,直至 ECX=0 或 ZF=1。

影响标志: 取决于后跟指令。

示例:

css 复制代码
MOV ESI, 0x11E8000  
MOV EDI, 0x11E8010  
MOV ECX, 5  
CLD  
REP MOVSB  ; 从 [ESI] 复制 5 字节到 [EDI]  

结论

在本章中,我们详细讲解了逆向工程中常用的主要汇编指令,涵盖了栈操作、数据传输、算术运算、程序执行、分支跳转、位操作、处理器控制以及字符串操作等多种指令类型,并通过示例演示了部分指令的使用方法。

在下一章中,我们将深入探讨基于栈的指令,并讲解代码调用约定的概念。这一概念在逆向工程中极为重要,你在实际逆向过程中会频繁遇到。

相关推荐
David WangYang38 分钟前
基于 IOT 的安全系统,带有使用 ESP8266 的语音消息
物联网·安全·语音识别
合作小小程序员小小店2 小时前
SDN安全开发环境中常见的框架,工具,第三方库,mininet常见指令介绍
python·安全·生成对抗网络·网络安全·网络攻击模型
网络研究院5 小时前
新的“MadeYouReset”方法利用 HTTP/2 进行隐秘的 DoS 攻击
网络·网络协议·安全·http·攻击·漏洞
guts°5 小时前
6-服务安全检测和防御技术
安全
sinat_2869451914 小时前
AI应用安全 - Prompt注入攻击
人工智能·安全·prompt
数据智能老司机1 天前
实现逆向工程——理解 x86 机器架构
安全·逆向
数据智能老司机1 天前
实现逆向工程——逆向工程的影响
安全·逆向
2301_780789661 天前
边缘节点 DDoS 防护:CDN 节点的流量清洗与就近拦截方案
安全·web安全·ddos
江拥羡橙1 天前
【基础-判断】HarmonyOS提供了基础的应用加固安全能力,包括混淆、加密和代码签名能力
安全·华为·typescript·harmonyos