【问题标题】:Smashing the stack not working粉碎堆栈不起作用
【发布时间】:2014-04-06 19:47:51
【问题描述】:

我已经完成了关于粉碎堆栈的演练。一个http://insecure.org/stf/smashstack.html 和一个我在这里找到的Trying to smash the stack。我知道会发生什么,但我无法让它正常工作。

这就像其他场景一样。我需要跳过 x=1 并打印 0 作为 x 的值。

我编译:

gcc file.c

原代码:

void function(){
    char buffer[8];
}

void main(){
    int x;
    x = 0;
    function();
    x = 1;
    printf("%d\n", x);
}

当我跑步时

objdump -dS a.out

我明白了

0000000000400530 <function>:
  400530:       55                      push   %rbp
  400531:       48 89 e5                mov    %rsp,%rbp
  400534:       5d                      pop    %rbp
  400535:       c3                      retq

0000000000400536 <main>:
  400536:       55                      push   %rbp
  400537:       48 89 e5                mov    %rsp,%rbp
  40053a:       48 83 ec 20             sub    $0x20,%rsp
  40053e:       89 7d ec                mov    %edi,-0x14(%rbp)
  400541:       48 89 75 e0             mov    %rsi,-0x20(%rbp)
  400545:       c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
  40054c:       b8 00 00 00 00          mov    $0x0,%eax
  400551:       e8 da ff ff ff          callq  400530 <function>
  400556:       c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%rbp)
  40055d:       8b 45 fc                mov    -0x4(%rbp),%eax
  400560:       89 c6                   mov    %eax,%esi
  400562:       bf 10 06 40 00          mov    $0x400610,%edi
  400567:       b8 00 00 00 00          mov    $0x0,%eax
  40056c:       e8 9f fe ff ff          callq  400410 <printf@plt>
  400571:       c9                      leaveq
  400572:       c3                      retq
  400573:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40057a:       00 00 00
  40057d:       0f 1f 00                nopl   (%rax)

在函数中,我需要计算出返回地址超出缓冲区起始位置的字节数。我不确定这个值。但是由于从函数开始到返回有 6 个字节;我会在缓冲区中添加 7 个字节吗?

那我需要跳过指令 x=1; 而且由于该指令的长度为 7 个字节。我要加 7 来返回指针吗?

这样的?

void function(){
    char buffer[8];
    int *ret = buffer + 7;
    (*ret) += 7;
}

void main(){
    int x;
    x = 0;
    function();
    x = 1;
    printf("%d\n", x);
}

这会引发警告:

warning: initialization from incompatible pointer type [enabled by default]
  int *ret = buffer1 + 5;
         ^

输出为 1。我做错了什么?你能解释一下如何正确地做到这一点以及为什么它是正确的方法吗?

谢谢。

【问题讨论】:

    标签: c function unix stack


    【解决方案1】:

    尝试下面的函数,我为 32 位编译器编写了它,尝试使用 (-m32 gcc flag) 或者稍加努力,您可以使其与您的 64 位编译器一起使用(请注意,在您的 objdump 列表中您在调用function 和下一条指令之间得到了7 字节偏移量,因此请使用7 而不是8

    void function(void)
    {
        unsigned long *x;
        /* &x will more likely be at -4(ebp) */
        /* Adding 1 (+4) gets us to stored ebp */
        /* Adding 2 (+8) gets us to stored return address */
        x = (unsigned long *)(&x + 2);
    
        /* This is the tricky part */
        /* TODO: On my 32-bit compiler gap between call to function
           and the next instruction is 8 */
        *x += 8;
    }
    

    【讨论】:

    • 谢谢。我不得不使用 4 而不是 2。但它有效。
    【解决方案2】:

    我们知道自动变量是在堆栈上创建的——因此获取自动变量的地址会产生一个指向堆栈的指针。当你调用一个 void 函数时,它的返回地址被压入堆栈,该地址的大小取决于你的平台(通常为 4 或 8 个字节)。因此,如果您将自动变量的地址传递给函数,然后覆盖该地址之前的内存,则会损坏返回地址并破坏堆栈。这是一个例子:

    #include <stdlib.h>
    #include <stdio.h>
    
    static void f(int *p)
    {
        p[0] = 0x30303030;
        p[1] = 0x31313131;
        *(p - 1) = 0x35353535;
        *(p - 2) = 0x36363636;
    }
    
    int main()
    {
        int a = 0x41424344;
        int b = 0x45464748;
        int c = 0x494a4b5c;
        f(&b);
        printf("%08x %08x %08x\n", a, b, c);
        return 0;
    }
    

    我在 linux 上用 'gcc -g' 编译了这个,然后在 gdb 下运行得到了这个:

    Program received signal SIGSEGV, Segmentation fault.
    0x000000000040056a in f (p=0x7fffffffde74) at smash.c:10
    10  }
    (gdb) bt
    #0  0x000000000040056a in f (p=0x7fffffffde74) at smash.c:10
    #1  0x3636363600400594 in ?? ()
    #2  0x3030303035353535 in ?? ()
    #3  0x494a4b5c31313131 in ?? ()
    #4  0x0000000000000000 in ?? ()
    (gdb)
    

    如您所见,父函数地址现在包含我的一些幻数。我在 64 位 linux 上运行它,所以我真的应该使用 64 位整数来完全覆盖返回地址 - 因为它是我保持低位字不变。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多