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

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

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

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

章节结构

本章将涵盖以下主题:

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

学习目标

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

不同的汇编语言指令

指令是汇编代码的基本构建块。指令由操作码(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]  

结论

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

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

相关推荐
用户9623779544820 小时前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机1 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954481 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star1 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954481 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher3 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
一次旅行6 天前
网络安全总结
安全·web安全
red1giant_star6 天前
手把手教你用Vulhub复现ecshop collection_list-sqli漏洞(附完整POC)
安全
ZeroNews内网穿透6 天前
谷歌封杀OpenClaw背后:本地部署或是出路
运维·服务器·数据库·安全