一、x86基础寄存器(逆向工程核心基础)

x86架构的寄存器是指令操作的核心载体,逆向中需精准掌握寄存器的用途、分类及数据流向,32位x86核心寄存器分为以下几类:

1. 通用寄存器(数据操作核心)

通用寄存器用于存储数据、地址、参数等,32位寄存器可拆分为16位/8位子寄存器(如EAX→AX→AH/AL),逆向中需关注子寄存器的操作(如单字节/双字节数据处理)。

32位寄存器 16位子寄存器 8位子寄存器 核心用途(逆向场景)
EAX AX AH/AL 累加器:算术运算、函数返回值(Windows API返回值默认存EAX)、系统调用号
EBX BX BH/BL 基址寄存器:全局变量指针、内存基址(如PEB/TEB偏移计算)
ECX CX CH/CL 计数器:循环计数(REP指令)、Fastcall/Thiscall参数传递(第1参数/this指针)
EDX DX DH/DL 数据寄存器:大数运算(除法余数、64位数据高32位)、Fastcall第2参数
ESI SI SIL 源变址寄存器:字符串操作(MOVS/LODS)源地址、数据拷贝源指针
EDI DI DIL 目的变址寄存器:字符串操作(MOVS/STOS)目的地址、数据拷贝目的指针
EBP BP BPL 基址指针:栈帧基址(逆向中通过EBP偏移定位局部变量/参数)
ESP SP SPL 栈指针:始终指向栈顶(逆向中跟踪栈帧变化、栈平衡)

逆向关键

2. 段寄存器(内存寻址辅助)

段寄存器在保护模式下用于定位内存段,逆向中需重点关注FS寄存器(关联TEB/PEB):

寄存器 核心用途(逆向场景)
CS 代码段:指向当前执行指令的代码段(.text段)
DS 数据段:指向全局数据段(.data/.rdata)
SS 栈段:指向栈段(栈帧所在内存区域)
ES/FS/GS 附加段:FS在Windows中指向TEB(线程环境块),是反调试分析的核心

3. 指令指针寄存器(执行流核心)

寄存器 32位名称 核心用途(逆向场景)
IP EIP 指令指针:指向当前即将执行的指令地址(逆向中跟踪执行流、断点设置核心)

逆向关键:EIP无法直接修改(仅能通过JMP/CALL/RET/INT等指令间接修改),是控制流分析的核心。

4. 标志寄存器(状态判断核心)

标志寄存器(EFLAGS)存储指令执行后的状态,是条件跳转(Jcc)、条件移动(CMOVcc)的判断依据,核心标志位如下:

标志位缩写 名称 含义
ZF 零标志 运算结果为0则置1,否则置0(JE/JNE的判断依据)
SF 符号标志 运算结果最高位为1(负数)则置1,否则置0(JG/JL的判断依据)
CF 进位标志 无符号运算产生进位/借位则置1(JA/JB/ADC/SBB的判断依据)
OF 溢出标志 有符号运算溢出则置1(JO/JNO/JG/JL的判断依据)
PF 奇偶标志 运算结果低8位中1的个数为偶数则置1(位运算/字节操作辅助判断)
IF 中断标志 控制CPU是否响应可屏蔽中断(反调试中可能通过CLI/STI修改)

二、汇编基本结构(x86实模式/保护模式)

x86汇编程序的核心结构分为段定义数据段代码段栈段三大部分,逆向中需重点关注内存布局与指令执行流:

1. 段结构(保护模式下)

; 典型NASM格式结构
section .data       ; 数据段:只读/可读写常量(全局变量、字符串、常量)
    msg db "hello",0x00
    num dd 123      ; 4字节整型常量

section .bss        ; 未初始化数据段:逆向中常为全局未初始化变量
    buf resb 100    ; 预留100字节缓冲区

section .text       ; 代码段:指令执行区,逆向核心分析区域
    global _start   ; 入口点(Linux)/ main(Windows)
_start:
    ; 指令执行流
    mov eax, 1      ; sys_exit调用
    int 0x80        ; 系统调用

2. 逆向视角的结构要点

三、核心指令体系(逆向高频指令)

1. 数据传输指令(逆向最基础、最高频)

数据传输指令负责在寄存器、内存、立即数间移动数据,逆向中需关注数据流向(如参数传递、加密数据搬运)。

指令 格式 功能 逆向场景
MOV MOV reg, mem/imm/reg 数据移动(不影响标志位) 变量赋值、参数传递
LEA LEA reg, mem 加载有效地址(计算地址) 数组索引、指针运算
PUSH/POP PUSH reg/mem; POP reg 入栈/出栈 函数调用、栈帧构建
XCHG XCHG reg, reg/mem 交换数据 加密算法、寄存器暂存
CMOVcc CMOVZ reg, mem 条件移动(依标志位) 无分支条件判断(反调试)
MOVSX/MOVZX MOVSX reg, reg8/16 符号/零扩展移动 整型类型转换(如char→int)

逆向示例

lea eax, [ebp+var_4]  ; 计算局部变量var_4的地址(而非取值)
movsx ebx, byte ptr [eax] ; 单字节符号扩展为4字节(处理负数)

2. 算数运算指令(逆向中加密/校验/数值计算核心)

指令 格式 功能 影响标志位
ADD/SUB ADD reg, mem/imm 加减运算 ZF/SF/CF/OF/AF/PF
MUL/IMUL IMUL reg, mem/imm 无符号/有符号乘法 CF/OF(MUL)
DIV/IDIV DIV reg 无符号/有符号除法 无(商→AX,余数→DX)
INC/DEC INC reg 自增/自减(不影响CF) ZF/SF/OF/AF/PF
NEG NEG reg 取反(等价于0 - reg) 同SUB
ADC/SBB ADC reg, imm 带进位/借位加减 同ADD/SUB

逆向关键

3. 位操作指令(逆向中加密/压缩/硬件交互核心)

指令 格式 功能 影响标志位
AND/OR/XOR XOR reg, mem/imm 按位与/或/异或 ZF/SF/PF(CF/OF=0)
NOT NOT reg 按位取反
SHL/SHR SHL reg, imm 逻辑左移/右移(空位补0) CF/ZF/SF/OF/PF
SAL/SAR SAR reg, imm 算术左移/右移(SAR补符号位) 同SHL/SHR
ROL/ROR ROL reg, imm 循环左移/右移(进位参与循环) 同SHL
BT/BTC/BTR BT reg, imm 位测试/测试并取反/测试并复位 CF(目标位值)

逆向示例

xor eax, eax        ; 快速清零寄存器(比mov eax,0更高效)
shl ebx, 3          ; 等价于ebx *= 8(逆向中识别乘除优化)
bt ecx, 7           ; 测试ecx第7位是否为1(结果存CF)

4. 逻辑比较指令(控制流分支的基础)

比较指令本质是“减法但不保存结果,仅更新标志位”,逆向中需结合标志位分析分支条件。

指令 格式 功能 影响标志位
CMP CMP reg, mem/imm 比较(reg - mem/imm) 同SUB
TEST TEST reg, mem/imm 按位与(仅更新标志位) 同AND
SCAS SCASB/SCASW/SCASD 串比较(AL/AX/EAX - [EDI]) 同CMP

逆向关键

5. 控制转移指令(逆向中分析执行流的核心)

控制转移指令改变EIP(指令指针),分为无条件跳转条件跳转函数调用/返回三类:

(1)无条件转移

指令 功能 逆向场景
JMP 无条件跳转 分支、循环、壳的跳转
CALL 调用函数(PUSH EIP+JMP) 函数调用、API调用
RET/RETN 函数返回(POP EIP) 函数结束、栈平衡

(2)条件跳转(Jcc)

基于标志寄存器的组合判断,是逆向中分析逻辑的核心:

指令 别名 条件 标志位组合 典型逆向场景
JE JZ 相等/零 ZF=1 字符串比较结束、循环终止
JNE JNZ 不等/非零 ZF=0 循环继续、条件分支
JG JNLE 有符号大于 SF=OF 且 ZF=0 数值范围判断(如x>10)
JGE JNL 有符号大于等于 SF=OF 数值判断(x≥0)
JL JNGE 有符号小于 SF≠OF 数值判断(x<5)
JLE JNG 有符号小于等于 SF≠OF 或 ZF=1 数值判断(x≤0)
JA JNBE 无符号高于 CF=0 且 ZF=0 地址/长度比较(如buf_len>100)
JAE JNB 无符号高于等于 CF=0 地址判断(ptr≥0x400000)
JB JNAE 无符号低于 CF=1 长度判断(len<256)
JBE JNA 无符号低于等于 CF=1 或 ZF=1 长度判断(len≤512)
JS - 结果为负 SF=1 负数处理、符号校验
JNS - 结果非负 SF=0 正数判断
JO - 溢出 OF=1 溢出异常检测、数值越界
JNO - 无溢出 OF=0 正常数值运算
JC - 有进位 CF=1 大数运算、校验和计算
JNC - 无进位 CF=0 大数运算正常分支

6. 栈操作指令(逆向中栈帧分析核心)

栈是x86逆向的核心(函数调用、局部变量、参数传递均依赖栈),栈操作指令需结合栈帧结构分析:

指令 格式 功能 逆向注意点
PUSH PUSH reg/mem/imm 栈顶指针ESP-4,数据入栈 逆向中跟踪栈内容变化
POP POP reg 栈顶数据出栈,ESP+4 注意POP后寄存器值变化
PUSHA/POPA - 所有通用寄存器入栈/出栈 保护现场(壳/调试器常用)
ENTER/LEAVE ENTER imm16, imm8 构建/销毁栈帧(等价于PUSH EBP; MOV EBP,ESP; SUB ESP,imm) 函数入口/出口快速识别

逆向核心:栈的生长方向为高地址→低地址,ESP始终指向栈顶,EBP为栈帧基址(逆向中通过EBP偏移定位参数/局部变量)。

7. 字符串操作指令(逆向中字符串处理/内存拷贝核心)

字符串指令通过ESI(源地址)、EDI(目的地址)、ECX(长度)、EAX(比较值)配合,批量处理内存数据,逆向中常出现在字符串拷贝、加密、校验场景:

指令 格式 功能 逆向场景
MOVS MOVSB/MOVSW/MOVSD 串拷贝([ESI]→[EDI]) 内存拷贝、数据搬运
LODS LODSB/LODSW/LODSD 串加载([ESI]→AL/AX/EAX) 读取字符串/数据块
STOS STOSB/STOSW/STOSD 串存储(AL/AX/EAX→[EDI]) 内存填充(如memset)
REP REP MOVSB 重复执行(ECX≠0) 批量拷贝(如strcpy)
REPE/REPNE REPE SCASB 相等/不等时重复 字符串比较(如strcmp)

逆向示例

; 等价于memset(edi, 0, ecx)
xor eax, eax    ; 填充值为0
rep stosb       ; 重复将AL写入[EDI],ECX次,EDI自动递增

四、TEB/PEB与反调试技术(逆向核心对抗场景)

TEB(线程环境块)、PEB(进程环境块)是Windows系统中存储进程/线程信息的核心结构,反调试技术常通过读取这些结构中的标志位检测调试器。

1. 核心结构关系

2. 基于TEB/PEB的反调试方法(逆向需识别)

反调试方式 汇编实现 逆向识别要点
检测BeingDebugged标志 mov eax, fs:[0x30]
mov al, [eax+0x02]
test al, al
jnz Debugged
跟踪FS:[0x30]访问,检查PEB+0x02
检测PEB堆标志 mov eax, fs:[0x30]
mov eax, [eax+0x10]
test dword ptr [eax+0x14], 0x40
访问ProcessHeap+0x14(HeapFlags)
检测调试端口(PEB+0xBC) mov eax, fs:[0x30]
cmp dword ptr [eax+0xBC], 0
jne Debugged
PEB+0xBC为调试端口,非0则调试

3. 逆向应对思路

五、函数调用与栈帧(逆向中函数分析核心)

1. 函数的标准汇编结构(32位x86,以Stdcall为例)

一个完整的函数在汇编层面分为函数序言函数体函数尾声三部分,逆向中可通过这三部分快速识别函数边界:

函数阶段 典型汇编指令 核心作用 逆向识别特征
函数序言(Prologue) push ebp
mov ebp, esp
sub esp, n
push ebx/esi/edi(可选)
1. 保存旧栈帧基址(EBP)
2. 建立新栈帧(EBP=ESP)
3. 分配局部变量空间(ESP-n)
4. 保护非易失性寄存器(EBX/ESI/EDI)
函数开头固定出现push ebp + mov ebp, esp,是识别函数入口的核心特征
函数体(Body) 各类业务指令(运算、分支、调用子函数等) 实现函数核心逻辑 包含业务相关的指令流,如参数访问(EBP+8/12)、局部变量访问(EBP-4/8)、子函数CALL等
函数尾声(Epilogue) pop ebx/esi/edi(可选)
mov esp, ebp
pop ebp
retn n(Stdcall)/ ret(Cdecl)
1. 恢复非易失性寄存器
2. 销毁栈帧(ESP=EBP)
3. 恢复旧EBP
4. 函数返回并平衡栈
函数结尾固定出现mov esp, ebp + pop ebp + ret/retn,是识别函数出口的核心特征

逆向示例:标准函数结构汇编代码

; 函数:int Add(int a, int b) (Stdcall调用约定)
Add:
    ; 函数序言
    push ebp         ; 保存旧EBP
    mov ebp, esp     ; 建立新栈帧
    sub esp, 0x4     ; 分配1个局部变量(4字节)空间
    push esi         ; 保护非易失性寄存器ESI
    
    ; 函数体
    mov eax, [ebp+8]  ; 读取参数a(EBP+8为第一个参数)
    mov esi, [ebp+12] ; 读取参数b(EBP+12为第二个参数)
    add eax, esi      ; a + b,结果存EAX(返回值)
    mov [ebp-4], eax  ; 临时存入局部变量(可选)
    
    ; 函数尾声
    pop esi          ; 恢复ESI
    mov esp, ebp     ; 销毁局部变量空间(ESP回到EBP)
    pop ebp          ; 恢复旧EBP
    retn 0x8         ; 返回,平衡栈(参数a+b共8字节,Stdcall由被调用者平衡)

2. 函数嵌套堆栈结构(32位x86)

以“函数A调用函数B,B有2个局部变量、2个参数”为例,栈帧结构(高地址→低地址):

函数A的栈帧
函数B的局部变量2
函数B的局部变量1
上一层的ebp
返回地址
参数1
参数2
函数B的栈顶(ESP)

3. 函数调用约定(逆向中识别参数传递/栈平衡)

调用约定决定参数传递顺序、栈平衡责任、寄存器使用,是逆向中还原函数原型的关键:

调用约定 参数传递顺序 栈平衡责任 寄存器使用 典型场景
Cdecl 右→左 调用者 C/C++默认、可变参数函数(printf)
Stdcall 右→左 被调用者 Windows API(如MessageBoxA)
Fastcall 右→左 被调用者 ECX(第1参数)、EDX(第2参数) 快速调用(编译器优化)
Thiscall 右→左 被调用者 ECX=this指针 C++类成员函数
Syscall 寄存器 内核 EAX(系统调用号)、EBX/ECX/EDX(参数) Windows内核系统调用(如NtReadFile)

逆向识别要点

六、标志寄存器的高级用法(逆向中分析分支/运算)

1. 高级应用场景

七、逆向工程核心技巧总结

  1. 指令流分析:从入口点开始,跟踪EIP变化,结合Jcc/Call/Ret分析执行流;
  2. 栈帧还原:通过EBP偏移定位参数(EBP+8开始)、局部变量(EBP-4开始),还原函数原型;
  3. 标志位跟踪:CMP/TEST后紧跟Jcc,需先分析标志位组合,再判断分支逻辑;
  4. 反调试识别:关注FS:[0x30](TEB)、PEB偏移访问、标志位异常修改指令;
  5. 调用约定还原:通过栈平衡指令(ADD ESP/RETN n)、寄存器使用(ECX/EDX)识别调用约定。