6、汇编语言入门(x86/x64):寄存器详解与常用指令

好,咱们今天聊点硬核的。汇编语言,说白了就是CPU能直接听懂的话。你写C++、Python,最终都得翻译成汇编才能跑。做逆向工程,不懂汇编?那就像开车不看仪表盘——能走,但迟早要出事。

我个人习惯,学汇编先别急着背指令,先把“寄存器”搞明白。寄存器是什么?就是CPU内部的小型存储单元,速度比内存快几个数量级。你操作数据,得先把它搬到寄存器里,才能折腾。

6.1 通用寄存器:EAX、EBX、ECX、EDX

这四个是x86架构里的“老四样”。每个都有32位宽,在x64下扩展成了RAX、RBX、RCX、RDX,但低32位用法完全兼容。

寄存器 常用用途 我的经验
EAX 累加器,函数返回值通常放这里 逆向时看到EAX被赋值,八成是函数要返回了
EBX 基址寄存器,常用于数组基址 我遇到过EBX被当作全局指针用,改它游戏就崩了
ECX 计数器,循环次数、字符串操作常用 调试循环时盯着ECX看,比看代码快
EDX 数据寄存器,I/O操作、乘法结果高位 做除法时EDX存余数,这个坑我踩过好几次
小技巧:在Cheat Engine里搜索数值时,如果发现某个地址的值一直在变,先看看是不是EAX或ECX在频繁读写。很多时候,游戏的核心逻辑就藏在这几个寄存器里。

6.2 栈指针与基址指针:ESP、EBP

这两个寄存器管着“栈”——函数调用的核心数据结构。ESP指向栈顶,EBP指向栈底。你想想看,函数调用时参数怎么传?局部变量怎么存?全靠这俩指针。

我记得有一次逆向一个加壳程序,它把ESP的值改了,导致栈帧全乱套。我当时盯着OD看了半小时才反应过来——嗯,这是反调试的经典手法。

  • ESP:栈顶指针,push/pop操作直接影响它
  • EBP:栈底指针,用于访问函数参数和局部变量
  • 常见模式:函数开头通常有 push ebp; mov ebp, esp
注意:在x64下,有些编译器不再用EBP做帧指针,而是直接用ESP偏移。这时候逆向起来会更绕,你得习惯用ESP+偏移量来定位变量。

6.3 指令指针:EIP

EIP存着下一条要执行的指令地址。你不能直接改它,但可以通过jmp、call、ret来间接控制。说白了,程序怎么跑,全看EIP指向哪。

我曾经在调试一个外挂时,发现它把EIP改到了一个无效地址,结果游戏直接崩溃。这种手法在反调试里很常见——故意让EIP飞掉,让调试器跟丢。

6.4 常用指令详解

MOV:数据搬运工

MOV是最基础的指令,没有之一。它的作用就是把数据从一个地方搬到另一个地方。注意,不能直接从内存搬到内存,得经过寄存器中转。

MOV EAX, 12345678h    ; 把立即数放到EAX
MOV EBX, [EAX]        ; 把EAX指向的内存数据读到EBX
MOV [ECX], EDX        ; 把EDX的值写到ECX指向的内存
核心要点:MOV不改变标志寄存器。如果你要判断数据大小,得用CMP或TEST。

JMP:无条件跳转

JMP就是“跳到哪去”。它直接修改EIP的值。逆向时看到JMP,通常意味着代码逻辑的分支或循环。

JMP 00401000h    ; 直接跳到地址00401000
JMP EAX          ; 跳到EAX里存的地址

CALL:函数调用

CALL和JMP很像,但它多了一步:先把返回地址(当前EIP的下一条)压栈,再跳转。这样函数执行完,RET指令就能从栈里弹出地址,回到调用点继续跑。

CALL 00402000h    ; 调用地址00402000处的函数
; 函数执行完后,RET会回到这里

我个人习惯,逆向时看到CALL,先别急着跟进去。看看它压栈的参数是什么,很多时候光看参数就能猜出函数功能。

CMP:比较指令

CMP本质上是做减法,但不保存结果,只影响标志寄存器。后面通常跟着条件跳转指令,比如JE、JNE、JG等。

CMP EAX, 100    ; 比较EAX和100
JE  label        ; 如果相等,跳到label

ADD/SUB:加减法

这两个指令太基础了,但要注意:它们会影响标志寄存器。特别是溢出标志OF和进位标志CF,做多字节运算时经常用到。

ADD EAX, 10     ; EAX = EAX + 10
SUB EBX, ECX    ; EBX = EBX - ECX

6.5 标志寄存器:EFLAGS

标志寄存器是个“状态位集合”,每个位代表一个状态。你不需要记住所有位,但下面这几个必须烂熟于心:

标志位 名称 什么时候置1
ZF 零标志 运算结果为0时
CF 进位标志 无符号运算溢出时
OF 溢出标志 有符号运算溢出时
SF 符号标志 结果为负数时
避坑指南:我曾经在分析一个游戏伤害计算时,发现它用CMP比较后直接跟了JG(有符号大于跳转)。但伤害值明明是无符号的,结果导致负数伤害被误判为超大正数。嗯,这就是CF和OF没分清的后果。

6.6 知识体系总览

下面这张图,把本章的核心知识点串起来了。你保存下来,以后忘了随时看。

x86汇编核心知识体系 通用寄存器 EAX EBX ECX EDX 栈指针寄存器 ESP EBP 指令指针 EIP MOV ADD SUB JMP CALL RET CMP TEST 标志寄存器 EFLAGS ZF 零标志 CF 进位标志 OF 溢出标志 SF 符号标志

这张图你看明白了吗?寄存器是CPU的“工作台”,指令是“工具”,标志寄存器是“状态灯”。三者配合,才能让程序跑起来。逆向时,你盯着这几个东西看,就能猜出程序在干什么。

总结一句话:寄存器是逆向工程师的“眼睛”。你看懂了寄存器,就看懂了程序的灵魂。

公众号:蓝海资料掘金营,微信deep3321