📌 Pwn 核心寄存器速查笔记
在 64 位系统(x86_64)中,寄存器通常以 R 开头(如 RAX,64位);在 32 位系统(x86)中,以 E 开头(如 EAX,32位)。以下主要以 64 位为例。
1. 函数调用约定与参数寄存器(Pwn 核心)
在 64 位 Linux(System V AMD64 ABI)中,函数调用的前 6 个参数通过寄存器传递,这是构造 ROP 链(控制 rdi, rsi 等)时最频繁打交道的寄存器:
RDI(Destination Index):第 1 个参数。- Pwn 场景:执行
system("/bin/sh")时,RDI必须指向"/bin/sh"的地址。
- Pwn 场景:执行
RSI(Source Index):第 2 个参数。- Pwn 场景:控制
read(0, buf, size)的写入缓冲区地址。
- Pwn 场景:控制
RDX(Data Register):第 3 个参数。- Pwn 场景:控制
read或write的长度(size),或者在mprotect中控制权限(如7代表可读可写可执行)。
- Pwn 场景:控制
RCX:第 4 个参数。R8:第 5 个参数。R9:第 6 个参数。
💡 注意:如果参数超过 6 个,剩下的参数会通过栈(Stack)传递。而在 32 位系统中,所有参数默认都通过栈传递。
2. 特殊功能寄存器
RAX(Accumulator Register):累加器 / 函数返回值 / 系统调用号。- 返回值:函数执行完毕后,返回值通常存放在
RAX中(例如pwntools接收泄露地址时就是看它)。 - 系统调用(Syscall):在利用
syscall触发execve时,必须先将系统调用号(64位下execve是59,即0x3b;read是0;write是1)存入RAX。
- 返回值:函数执行完毕后,返回值通常存放在
RIP(Instruction Pointer):指令指针寄存器。- Pwn 场景:指向当前即将执行的指令地址。劫持程序执行流(PC Control)的本质就是控制
RIP的值。
- Pwn 场景:指向当前即将执行的指令地址。劫持程序执行流(PC Control)的本质就是控制
3. 栈帧控制寄存器(堆栈溢出核心)
RSP(Stack Pointer):栈顶指针。- Pwn 场景:指向当前栈帧的顶部。
push、pop、call、ret指令都会隐式修改RSP的值。在栈溢出中,RSP决定了当前 ROP 链的执行位置(Stack Pivoting 技术就是通过修改RSP来将栈劫持到堆或其他内存区域)。
- Pwn 场景:指向当前栈帧的顶部。
RBP(Base Pointer):栈底指针。- Pwn 场景:指向当前栈帧的底部。常用于基址寻址局部变量。在栈溢出漏洞中,通常需要覆盖
Saved RBP(EBP)来到达返回地址;在某些特殊的溢出(如off-by-one导致 one-byte overflow)中,通过修改RBP的最低字节可以实现Leave-Ret触发的栈劫持。
- Pwn 场景:指向当前栈帧的底部。常用于基址寻址局部变量。在栈溢出漏洞中,通常需要覆盖
4. 通用数据与通用寄存器
虽然它们有默认含义,但在实际汇编代码和 ROP 链中,经常被用作临时的数据中转站:
RBX(Base Register):基地址寄存器,常用于内存寻址或作为通用寄存器。R10-R15:通用寄存器。在 ROP 链中,如果找不到直接给RDI/RSI/RDX赋值的 Gadget,有时需要利用类似__libc_csu_init中的 Gadget(万能 Gadget),通过R12~`R15` 中转来控制参数寄存器。
5. 状态与段寄存器(辅助分析)
RFLAGS:标志寄存器(如ZF零标志,SF符号标志)。- Pwn 场景:决定了条件跳转(如
je,jne等格式的花指令或业务逻辑判断)是否成立。
- Pwn 场景:决定了条件跳转(如
FS/GS:段寄存器。- Pwn 场景:在 Linux 64 位中,
FS寄存器常用于指向线程局部存储(TLS)。Canary(栈保护金丝雀)的值就保存在fs:[0x28]处。 分析绕过 Canary 时会涉及到这个概念。
- Pwn 场景:在 Linux 64 位中,
check list
接受泄露的地址
1 | puts_leak = p.recv(6) |
自动寻找format的offset
1 | from pwn import * |
使用python代码将recv()的内容还原到栈中
1 | def print_stack_visual(full_stack_bytes, start_addr=0x7ffcfdec5000): |