Stack Backstrace
基础知识
stack frame
Stack frame(栈帧)是一个为函数保留的区域,用来存储关于参数、局部变量和返回地址的信息。
寄存器
EIP
$eip:instruction pointer
EIP寄存器存放下一条要执行的指令地址。
EBP
$ebp:frame pointer
EBP寄存器指向stack frame的基地址。
If $ebp for some stack frame is stored at addr X then $eip for that frame is stored at addr X + 4.
ESP
$esp:Stack Pointer(SP)
ESP寄存器指向栈顶。
汇编指令
CALL操作
把返回地址压入栈中并且跳转到调用函数开始处并且执,具体步骤:
1.Push eip : the return address
2.Push ebp : saves previous frame pointer
3.Copy sp into fp : ebp = esp
4.The new AR’s frame pointer will be the previous value of the stack pointer
5.Advance sp (esp) for allocations on stack (that is, decrement it)
LEAVE操作
1.Load ebp into esp: move %ebp, %esp
2.Restore ebp from the stack: pop %ebp
RET操作
调用RET前,程序员要保证栈指针ESP指向的位置刚好为CALL指令保存的返回地址(EIP),具体步骤:
1.Move contents of ebp into esp.
2.Increment esp by 4.
3.esp should now point to eip.
4.RET will load the value stored in esp into the eip register then jump to that value.
栈跟踪
代码
gcc -g test.c -o test
#include
void funcc(int c)
{
printf("%d\n", c);
}
void funcb(int b, int c)
{
printf("%d\n", b);
funcc(c);
}
void funca(int a, int b, int c)
{
printf("%d\n", a);
funcb(b, c);
}
void main()
{
int a = 4;
int b = 3;
int c = 2;
int d = 1;
funca(a, b, c);
printf("%d\n", d);
}
gdb跟踪
1.对函数funcc设置断点,运行并查看寄存器信息,EIP为0x8048423,EBP为0xbfffefa8。
2.对地址0x8048423反汇编,在funcc的栈帧中,EIP存放下一条要执行的语句地址。
3.通过funcc栈帧中EBP指向基地址+4来读取返回地址(0xbfffefa8+4),读取该地址信息得到0x0804845c。
对地址0x0804845c反汇编后得到该地址指向leave操作,就是说funcb调用完funcc后要执行的下一条指令就是leave指令。
4.执行完funcc后进入到funcb的栈帧,查看寄存器信息, EIP为0x804845c,EBP为0xbfffefc8。
5.对地址0x804845c反汇编,在funcb的栈帧中,EIP存放下一条要执行的语句地址。
6.通过funcb栈帧中EBP指向基地址+4来读取返回地址(0xbfffefc8+4),读取该地址信息得到0x0804845c。
对地址0x0804845c反汇编后得到该地址指向leave操作,就是说funca调用完funcb后要执行的下一条指令就是leave指令。
7.执行完funcb后进入到funca的栈帧,查看寄存器信息, EIP为0x8048489,EBP为0xbfffefe8。
8.对地址0x8048489反汇编,在funca的栈帧中,EIP存放下一条要执行的语句地址。
9.通过funca栈帧中EBP指向基地址+4来读取返回地址(0xbfffefe8+4),读取该地址信息得到0x0804845c。
对地址0x080484d0反汇编,main调用完funca后要调用的printf。
10.执行完funca后进入到main的栈帧,查看寄存器信息, EIP为0x80484d0,EBP为0xbffff018。
11.对地址0x80484d0反汇编,在main的栈帧中,EIP存放下一条要执行的语句地址。
12.通过funca栈帧中EBP指向基地址+4来读取返回地址(0xbffff018+4),读取该地址信息得到0xb7e30a83。
对地址0xb7e30a83反汇编,main返回后就会执行exit操作。