【转】根据EBP得到函数堆栈

【原文地址】http://blog.chinaunix.net/uid-8118579-id-2034131.html

如果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),然后利用gdbdisassem命令得到函数调用的地址。以此类推,我们可以得到整个函数调用的堆栈。

一个例子:

#include

void funcc(int c)

{

    printf("%d ", c);

}

void funcb(int b, int c)

{

    printf("%d ", b);

    funcc(c);

}

void funca(int a, int b, int c)

{

printf("%d ", a);  

funcb(b, c);

}

main()

{

    int a = 4;

    int b = 3;

    int c = 2;

    int d = 1;

    funca(a, b, c);

    printf("%d ", 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 ", 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<funcc+11>

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 <funcb+0>:   push   %rbp

0x00000000004004b8 <funcb+1>:   mov    %rsp,%rbp

0x00000000004004bb <funcb+4>:   sub    $0x10,%rsp

0x00000000004004bf <funcb+8>:   mov    %edi,0xfffffffffffffffc(%rbp)

0x00000000004004c2 <funcb+11>:  mov    %esi,0xfffffffffffffff8(%rbp)

0x00000000004004c5 <funcb+14>:  mov    0xfffffffffffffffc(%rbp),%esi

0x00000000004004c8 <funcb+17>:  mov    $0x400658,%edi

0x00000000004004cd <funcb+22>:  mov    $0x0,%eax

0x00000000004004d2 <funcb+27>:  callq  0x400398<printf@plt>

0x00000000004004d7 <funcb+32>:  mov    0xfffffffffffffff8(%rbp),%edi

0x00000000004004da <funcb+35>:  callq  0x400498

0x00000000004004df <funcb+40>:  leaveq

0x00000000004004e0 <funcb+41>:  retq

(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 <funca+0>:   push   %rbp

0x00000000004004e2 <funca+1>:   mov    %rsp,%rbp

0x00000000004004e5 <funca+4>:   sub    $0x10,%rsp

0x00000000004004e9 <funca+8>:   mov    %edi,0xfffffffffffffffc(%rbp)

0x00000000004004ec <funca+11>:  mov    %esi,0xfffffffffffffff8(%rbp)

0x00000000004004ef <funca+14>:  mov    %edx,0xfffffffffffffff4(%rbp)

0x00000000004004f2 <funca+17>:  mov    0xfffffffffffffffc(%rbp),%esi

0x00000000004004f5 <funca+20>:  mov    $0x400658,%edi

0x00000000004004fa <funca+25>:  mov    $0x0,%eax

0x00000000004004ff <funca+30>:  callq  0x400398<printf@plt>

0x0000000000400504 <funca+35>:  mov    0xfffffffffffffff4(%rbp),%esi

0x0000000000400507 <funca+38>:  mov    0xfffffffffffffff8(%rbp),%edi

0x000000000040050a <funca+41>:  callq  0x4004b7

0x000000000040050f <funca+46>:  leaveq

0x0000000000400510 <funca+47>:  retq

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 <main+0>:    push   %rbp

0x0000000000400512 <main+1>:    mov    %rsp,%rbp

0x0000000000400515 <main+4>:    sub    $0x10,%rsp

0x0000000000400519 <main+8>:    movl   $0x4,0xfffffffffffffff0(%rbp)

0x0000000000400520 <main+15>:   movl   $0x3,0xfffffffffffffff4(%rbp)

0x0000000000400527 <main+22>:   movl   $0x2,0xfffffffffffffff8(%rbp)

0x000000000040052e <main+29>:   movl   $0x1,0xfffffffffffffffc(%rbp)

0x0000000000400535 <main+36>:   mov    0xfffffffffffffff8(%rbp),%edx

0x0000000000400538 <main+39>:   mov    0xfffffffffffffff4(%rbp),%esi

0x000000000040053b <main+42>:   mov    0xfffffffffffffff0(%rbp),%edi

0x000000000040053e <main+45>:   callq  0x4004e1

0x0000000000400543 <main+50>:   mov    0xfffffffffffffffc(%rbp),%esi

0x0000000000400546 <main+53>:   mov    $0x400658,%edi

0x000000000040054b <main+58>:   mov    $0x0,%eax

0x0000000000400550 <main+63>:   callq  0x400398<printf@plt>

0x0000000000400555 <main+68>:   leaveq

0x0000000000400556 <main+69>:   retq

End of assembler dump.

 

So we got the backtrace as main->funca->funcb->funcc

原文地址:https://www.cnblogs.com/lijinlei/p/4728607.html