分类: LINUX
2010-10-28 15:21:34
如果stack没有corruption的话,我们可以利用GDB的bt命令得到function的backtrace.
但如果stack corruption了,gdb是不能帮我们得到backtrace的。本文介绍了根据EBP得到backtrace的方法,这种方法只适用于X86架构。
栈的基本模型
参数N |
↓高地址 |
参数… |
函数参数入栈的顺序与具体的调用方式有关 |
参数 3 | |
参数 2 | |
参数 1 | |
eip |
返回本次调用后,下一条指令的地址 |
ebp |
这里保存调用者的ebp,然后ebp寄存器会指向此时的栈顶。 |
临时变量1 |
|
临时变量2 |
|
临时变量3 |
|
临时变量… |
|
临时变量n |
↓低地址 |
函数调用发生的时候,先把函数参数(从右往左顺序压)压入stack,再压入函数调用的下条指令的address. 接着进入调用函数体中先执行"pushl %ebp"和"movl %esp, %ebp"(一般已经由编译器加入到函数头中了),接着就是把函数体中的局部变量压入栈中。再遇到函数的调用的嵌套则依此类推。
这个方法的基本原理是先得到EBP中的地址,根据这个地址可以得到调用者的ebp的地址,然后我们可以根据调用者的EBP得到调用函数时的指令地址(ebp+4, 32-bit OS),然后利用gdb的disassem命令得到函数调用的地址。以此类推,我们可以得到整个函数调用的堆栈。
一个例子:
#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);
}
main()
{
int a = 4;
int b = 3;
int c = 2;
int d = 1;
funca(a, b, c);
printf("%d\n", d);
}
Generating a binary with debug info using GCC.
gcc –g –o 12 12.c
Then using gdb to get the backtrace according to EBP.
gdb 12
(gdb) b funcc
Breakpoint 1 at 0x4004a3: file 12.c, line 5.
(gdb) r
Starting program: /home/jx/example/12
4
3
Breakpoint 1, funcc (c=2) at 12.c:5
5 printf("%d\n", c);
(gdb) info reg
rax 0x2 2
rbx 0x3a11c19bc0 249406004160
rcx 0x3a1214a760 249411446624
rdx 0x3a1214b920 249411451168
rsi 0x2aaaaaaac000 46912496123904
rdi 0x2 2
rbp 0x7fff60038730 0x7fff60038730 =è64bit OS, ebp has changed to rbp.
rsp 0x7fff60038720 0x7fff60038720
r8 0xffffffff 4294967295
r9 0x3a11f12a40 249409120832
r10 0x22 34
r11 0x246 582
r12 0x0 0
r13 0x7fff60038870 140734804232304
r14 0x0 0
r15 0x0 0
rip 0x4004a3 0x4004a3
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) x /8x 0x7fff60038738(0x7fff60038730 + 8, 64bit OS, rbp + 8, eip)
(gdb) x /2x 0x7fff60038738
0x7fff60038738: 0x004004df 0x00000000
(gdb) disassem 0x004004df
Dump of assembler code for function funcb:
0x00000000004004b7
0x00000000004004b8
0x00000000004004bb
0x00000000004004bf
0x00000000004004c2
0x00000000004004c5
0x00000000004004c8
0x00000000004004cd
0x00000000004004d2
0x00000000004004d7
0x00000000004004da
0x00000000004004df
0x00000000004004e0
(gdb) x /2x 0x7fff60038730 ==========èget upper stack’s rbp
0x7fff60038730: 0x60038750 0x00007fff
(gdb) x /2x 0x7fff60038758 ========è upper stack’s rip
0x7fff60038758: 0x0040050f 0x00000000
(gdb) disassem 0x0040050f
Dump of assembler code for function funca:
0x00000000004004e1
0x00000000004004e2
0x00000000004004e5
0x00000000004004e9
0x00000000004004ec
0x00000000004004ef
0x00000000004004f2
0x00000000004004f5
0x00000000004004fa
0x00000000004004ff
0x0000000000400504
0x0000000000400507
0x000000000040050a
0x000000000040050f
0x0000000000400510
End of assembler dump.
(gdb) x /2x 0x7fff60038750 =èget upper upper ebp from upper ebp
0x7fff60038750: 0x60038770 0x00007fff
(gdb) x /2x 0x7fff60038778 =èeip from ebp
0x7fff60038778: 0x00400543 0x00000000
(gdb) disassem 0x00400543
Dump of assembler code for function main:
0x0000000000400511
0x0000000000400512
0x0000000000400515
0x0000000000400519
0x0000000000400520
0x0000000000400527
0x000000000040052e
0x0000000000400535
0x0000000000400538
0x000000000040053b
0x000000000040053e
0x0000000000400543
0x0000000000400546
0x000000000040054b
0x0000000000400550
0x0000000000400555
0x0000000000400556
End of assembler dump.
So we got the backtrace as main->funca->funcb->funcc
chinaunix网友2010-10-29 14:57:27
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com