zoukankan      html  css  js  c++  java
  • 【转】根据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

  • 相关阅读:
    uni-app 小程序实现scroll-view 横向滑动效果的坑
    kafka常用指令
    vue之每个页面设置单独的title,keywords,description等
    mysql定时备份
    zabbix-mysql备份脚本
    第十五课:企业案例-kubernetes高可用集群架构设计
    第十四课:企业案例-微服务实现业务架构
    第十三课:微服务基本知识-微服务调用及运行过程
    第十二课:微服务基本知识-微服务组件
    第十一课:微服务基本知识-微服务架构与框架介绍
  • 原文地址:https://www.cnblogs.com/lijinlei/p/4728607.html
Copyright © 2011-2022 走看看