Loading... # 引言 最近在学习逆向,这里是浅浅记录的笔记。俗话说磨刀不误砍柴工,以前并没有严格的去要求自己去理解底层,只是知道有这个东西,技术债趁此机会补一补。 # 基本通用寄存器(General Purpose Registers) | 寄存器 | 名称 | 用途说明 | | -------- | ------ | ---------- | | EAX | 累加器(Accumulator) | 常用于算术/逻辑运算的结果。某些指令默认使用它(如`MUL`、`DIV`)。 | | EBX | 基址寄存器(Base) | 可用作指针,访问内存。常用于数据存储。 | |ECX | 计数器(Counter) | 用作循环计数器,很多循环/字符串操作指令默认用它计数。 | | EDX | 数据寄存器(Data) | 常与 EAX 配合用于乘法/除法(比如高位/低位)。 |# 指针与索引寄存器(Pointer and Index Registers) | 寄存器 | 名称 | 用途说明 | | --------------- | ------------------------------------- | -------------------------------------------------------------- | | ESI | 源索引寄存器(Source Index) | 在字符串处理(如`MOVS`,`LODS`)中用于指向源地址。 | | EDI | 目的索引寄存器(Destination Index) | 与 ESI 配合,用于字符串操作的目标地址。 | | EBP | 基址指针寄存器(Base Pointer) | 通常用于函数调用时保存栈帧基址,辅助访问函数参数和局部变量。 | | ESP | 栈指针寄存器(Stack Pointer) | 始终指向当前栈顶,在函数调用、返回、局部变量分配时使用。 | # 控制寄存器 | 寄存器 | 名称 | 用途说明 | | -------- | ------ | ---------- | | EIP | 指令指针寄存器(Instruction Pointer) | 存储下一条将要执行的指令地址,控制程序流程。不能直接修改,只能通过跳转/调用指令间接改变。 # 段寄存器 | 寄存器 | 名称 | 用途 | | -------- | ------ | ------ | | CS | Code Segment | 代码段寄存器,指向当前执行代码所在的段。配合`EIP`一起定位当前指令地址。 | | DS | Data Segment | 数据段寄存器,默认用于访问一般变量数据。 | | SS | Stack Segment | 栈段寄存器,默认用于`ESP`、`EBP`指向的内存访问。 | |ES | Extra Segment | 额外段寄存器,通常与字符串操作指令配合使用(比如`MOVS`、`STOS`)。 | | FS | FS Segment | 一般用于**线程局部存储(TLS)**,Windows 下很多结构(如 TEB)通过它访问。 | |GS | GS Segment | 类似 FS,通常也用于访问特定系统数据或线程相关数据(Linux 下使用较多)。 | # 小提示 * “E” 前缀表示 Extended(扩展)*,是对早期 16 位寄存器(AX, BX, etc.)的扩展。 * 在 64 位系统中,它们被扩展为 RAX、RBX、RCX、RDX、RSP、RBP、RSI、RDI、RIP 等 (E-->R)。 # 小栗子🌰 这里是一个简单的C语言的代码 ```c++ int add(int a, int b) { return a + b; } int main() { int result = add(3, 5); return 0; } ``` 转换成汇编语言大概是这个样子 ```diff main: push ebp ; ① 保存旧栈帧指针,方便返回时恢复 mov ebp, esp ; ② 设置新的栈帧基址,方便访问函数参数/局部变量 sub esp, 10h ; ③ 为局部变量分配空间(例如 result),这里是 16 字节 push 5 ; ④ 将参数 b 压栈,先压后用(右边的参数先压) push 3 ; ⑤ 再将参数 a 压栈 call add ; ⑥ 调用 add 函数,压入返回地址,然后跳转 add esp, 8 ; ⑦ 清理栈上两个参数(2 × 4 字节) mov [ebp-4], eax ; ⑧ 将 add 返回的结果(存在 eax)保存到局部变量 result mov eax, 0 ; ⑨ 返回值为 0,表示 main 函数结束 leave ; ⑩ 恢复 esp 和 ebp(等价于:mov esp, ebp → pop ebp) ret ; ⑪ 从栈中弹出返回地址到 EIP,跳回操作系统 add: push ebp ; ⑫ 保存调用者的栈帧指针 mov ebp, esp ; ⑬ 设置新的栈帧基址 mov eax, [ebp+8] ; ⑭ 读取参数 a 到 eax 寄存器 add eax, [ebp+0Ch] ; ⑮ 把参数 b 加到 eax 上 pop ebp ; ⑯ 恢复旧栈帧 ret ; ⑰ 弹出返回地址,跳回调用点 ``` ## 寄存器的用法 | 寄存器 | 用法说明 | | -------- | ---------- | | EAX | 存放`add`函数的返回值,调用后`EAX=8`,被保存到 result 中。 | | EBP | 建立栈帧,`[EBP+8]`和`[EBP+0Ch]`分别是函数参数 a 和 b 的位置。 | | ESP | 指向栈顶,`push`/`pop`会修改它。 | | EIP | `call`指令时保存下一条地址,跳转到`add`函数,执行完后`ret`取出返回地址继续执行。 ## 栈布局(add 函数执行时) ```diff ESP → +------------+ ← [EBP+0Ch] = b (5) | 参数 b | +------------+ ← [EBP+8] = a (3) | 参数 a | +------------+ | 返回地址 | +------------+ | 上一个 EBP | +------------+ ← EBP ``` © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏