在 Linux 下进行反汇编(如用 objdump、gdb、IDA、Ghidra 等)时,**“看栈帧”**通常是指理解:
ebp/rbp 和 esp/rsp 还原栈结构下面从原理 + 实际反汇编示例两个层面讲。
每次函数调用,都会在栈上分配一块空间,称为栈帧,一般包括:
高地址
|------------------|
| 参数(如有) |
|------------------|
| 返回地址 |
|------------------|
| 旧 rbp/ebp | <- 当前函数 rbp 指向这里
|------------------|
| 局部变量 |
|------------------|
| 临时数据 |
低地址
典型函数开头(prologue):
push ebp
mov ebp, esp
sub esp, 0x10 ; 分配局部变量空间
函数结束(epilogue):
mov esp, ebp
pop ebp
ret
访问方式:
[ebp+8]:第 1 个参数[ebp+12]:第 2 个参数[ebp-4]:第 1 个局部变量rdi, rsi, rdx, rcx, r8, r9rbp 作为帧指针(可被优化掉)典型代码:
push rbp
mov rbp, rsp
sub rsp, 0x20
访问:
[rbp-0x8]:局部变量[rbp+0x10]:栈上传参示例 C 代码:
int add(int a, int b) {
int c = a + b;
return c;
}
反汇编:
gcc -O0 -g -o test test.c
objdump -d -M intel test
看到:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov eax, [rbp-4]
add eax, [rbp-8]
mov [rbp-12], eax
mov eax, [rbp-12]
pop rbp
ret
分析:
rbp-4:参数 arbp-8:参数 brbp-12:局部变量 c(gdb) break add
(gdb) run
(gdb) info frame
输出示例:
Stack frame at 0x7fffffffe1a0:
rip = 0x401126 in add
saved rip = 0x40115a
called by frame at 0x7fffffffe1c0
info registers
重点看:
rsp / rbpripx/10x $rbp-0x20
或:
x/8xw $rsp
看到:
push rbp
mov rbp, rsp
→ 这是一个标准栈帧
sub rsp, xxxsub rsp, 0x40
→ 分配了 64 字节局部变量
rbp - x:局部变量rbp + x:参数 / 返回地址-O2 可能 没有 rbprsp 偏移访问| 位置 | 含义 |
|---|---|
rbp+8 |
返回地址 |
rbp+16 |
第 7 个参数 |
rbp |
旧 rbp |
rbp-8 |
局部变量 |
rsp |
栈顶 |
objdump / IDA / Ghidragdb + pwndbgpwndbg 的 stack 命令如果你愿意,可以:
我可以直接帮你“手拆栈帧”。