【问题标题】:Smashing the stack example3.c confusion砸栈example3.c混乱
【发布时间】:2012-10-11 23:04:36
【问题描述】:

文章可以在here找到。

我正在阅读有关粉碎堆栈的内容,并发现自己被困在 example3.c 上。

0x80004a3 <main+19>:    call   0x8000470 <function>
0x80004a8 <main+24>:    addl   $0xc,%esp
0x80004ab <main+27>:    movl   $0x1,0xfffffffc(%ebp)
0x80004b2 <main+34>:    movl   0xfffffffc(%ebp),%eax

作者指出我们要从0x80004a8跳转到0x80004b2,这个跳转是8个字节;作者如何确定这是 8 个字节?我重新创建了代码并通过objdump 发送它,发现它不是 8 个字节(我在 64 位机器上,但我确保使用 32 位编译):

8048452:    e8 b5 ff ff ff          call   804840c <function>
8048457:    c7 44 24 1c 01 00 00    movl   $0x1,0x1c(%esp)
804845e:    00 
804845f:    8b 44 24 1c             mov    0x1c(%esp),%eax
8048463:    89 44 24 04             mov    %eax,0x4(%esp)
8048467:    c7 04 24 18 85 04 08    movl   $0x8048518,(%esp)

作者还说“我们怎么知道要在返回地址上加 8?我们用了一个 先测试值(例如 1)" 他在哪里使用了这个测试值?

【问题讨论】:

  • 根据用户请求移至 StackOverflow。 (+1,好问题。)
  • 如果你像那篇文章中那样减去地址,你会得到 10 个字节 :) 检查我答案末尾的链接,偏移量是错误的。
  • 有回答说现在已经修改了。这是最新的revision

标签: c stack-overflow buffer-overflow disassembly


【解决方案1】:

我不是这样解释这篇文章的。据我了解,他想修改返回地址以便跳过x = 1; 分配,即他希望function 返回到将执行printf 的位置。

正如您在反汇编中看到的,分配是 8 个字节 (c7 44 24 1c 01 00 00 00),因此将返回地址向前移动 8 个字节会将其移过这条指令。至于“我们首先使用测试值”的评论..也许他只是意味着他在反汇编程序中查看了代码以找出长度,或者他尝试了不同的偏移量(?)。

【讨论】:

    【解决方案2】:

    文章中的位移错了,应该是10字节。当调用函数(或执行跳转)时,返回地址设置为等于指令指针+当前指令大小:

    ret = IP + Curr_Inst_size
    

    所以当函数调用返回时,指令指针应该等于0x80004a80x80004a3+调用指令大小):

        0x80004a3 <main+19>:    call   0x8000470 <function>
    --> 0x80004a8 <main+24>:    addl   $0xc,%esp            
        0x80004ab <main+27>:    movl   $0x1,0xfffffffc(%ebp)
        0x80004b2 <main+34>:    movl   0xfffffffc(%ebp),%eax
    

    但是,如果你想将指令指针设置为 0x80004b2跳过赋值,你也不可避免地必须跳过另一条指令 (addl $0xc,%esp) 才能到达那里,或者以其他方式也就是说,您需要在指令指针中添加(0x80004b2-0x80004a8) 字节或10 个字节以跳过这两条指令:

        0x80004a3 <main+19>:    call   0x8000470 <function>
        0x80004a8 <main+24>:    addl   $0xc,%esp            
        0x80004ab <main+27>:    movl   $0x1,0xfffffffc(%ebp)
    --> 0x80004b2 <main+34>:    movl   0xfffffffc(%ebp),%eax 
    

    实际指令大小取决于操作数、机器类型等。但在此示例中,addl 为 3 个字节长,movl 为 7 个字节长。你可以检查x86 Instruction Set Reference 的确切指令大小,或者你可以编译和反汇编这段代码,你会看到这两条指令有 10 个字节长:

    int main()
    {
        asm("addl  $0xc,%esp\n\
             movl  $0x1,0xfffffffc(%ebp)");
    
    }
    

    gdb:

    0x08048397 <+3>: 83 c4 0c               add    $0xc,%esp
    0x0804839a <+6>: c7 45 fc 01 00 00 00   movl   $0x1,-0x4(%ebp)
    

    herehere 在示例 3 中也有关于这个完全相同的问题的讨论。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-04
      • 2011-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-27
      • 2019-08-25
      相关资源
      最近更新 更多