【问题标题】:Confused by [ebp-0xc] instead of [ebp-4] in Art of Exploitation example在 Art of Exploitation 示例中被 [ebp-0xc] 而不是 [ebp-4] 弄糊涂了
【发布时间】:2021-05-11 10:15:05
【问题描述】:

我正在读这本书 黑客:剥削的艺术,第 2 版 并在简单的 C 程序中

#include <stdio.h>
int main()
{
    int i;  
    for (i = 0; i < 10; i++)
    {
        puts("Hello, world!\n");
    }
    return 0;
}

书上列出gdb debug会先修改ebp寄存器:

(gdb) x/i $eip 0x8048384 <main+16>: mov DWORD PTR [ebp-4],0x0

正如它所解释的那样 这条汇编指令会将 0 的值移动到位于 在存储在 EBP 寄存器中的地址,负 4。这是 C 变量 能够 i 存储在内存中; i 被声明为一个使用 4 个字节的整数 x86 处理器上的内存

这对我来说很有意义,但是当我在“非常旧的 I386”Linux 笔记本电脑上测试确切的步骤时,我得到了以下结果:

(gdb) x/i $eip => 0x4011b6 <main+29>:   mov    DWORD PTR [ebp-0xc],0x0

所以在我的笔记本电脑上,它显示的是 [ebp-0xc],而不是 [ebp-4]。 根据我的理解,“0xc”作为十六进制将是 12,所以它将是 12 字节?如果有,为什么?

这是我笔记本电脑上这个简单程序的整个汇编转储 (gdb) 反汇编 main

Dump of assembler code for function main:
   0x00401199 <+0>: lea    ecx,[esp+0x4]
   0x0040119d <+4>: and    esp,0xfffffff0
   0x004011a0 <+7>: push   DWORD PTR [ecx-0x4]
   0x004011a3 <+10>:    push   ebp
   0x004011a4 <+11>:    mov    ebp,esp
   0x004011a6 <+13>:    push   ebx
   0x004011a7 <+14>:    push   ecx
   0x004011a8 <+15>:    sub    esp,0x10
   0x004011ab <+18>:    call   0x4010a0 <__x86.get_pc_thunk.bx>
   0x004011b0 <+23>:    add    ebx,0x2e50
=> 0x004011b6 <+29>:    mov    DWORD PTR [ebp-0xc],0x0
   0x004011bd <+36>:    jmp    0x4011d5 <main+60>
   0x004011bf <+38>:    sub    esp,0xc
   0x004011c2 <+41>:    lea    eax,[ebx-0x1ff8]
   0x004011c8 <+47>:    push   eax
   0x004011c9 <+48>:    call   0x401030 <puts@plt>
   0x004011ce <+53>:    add    esp,0x10
   0x004011d1 <+56>:    add    DWORD PTR [ebp-0xc],0x1
   0x004011d5 <+60>:    cmp    DWORD PTR [ebp-0xc],0x9
   0x004011d9 <+64>:    jle    0x4011bf <main+38>
   0x004011db <+66>:    mov    eax,0x0
   0x004011e0 <+71>:    lea    esp,[ebp-0x8]
   0x004011e3 <+74>:    pop    ecx
   0x004011e4 <+75>:    pop    ebx
   0x004011e5 <+76>:    pop    ebp
   0x004011e6 <+77>:    lea    esp,[ecx-0x4]
   0x004011e9 <+80>:    ret    
End of assembler dump.

【问题讨论】:

  • 你能发布你的代码吗?你在一个函数内吗?例如,那些额外的 8 个字节可能已为返回值和本地参数保留。
  • 代码很简单 code (gdb) list main 1 #include 2 3 int main() 4 { 5 int i; 6 for (i = 0; i code
  • 我绝对需要完善我的汇编程序 :) 无论如何,请考虑一些事情。 1)您正在调试模式下编译它,不是吗? 2)将您的代码移动到一个函数中,只是为了测试ebp-0x4 确实被使用了。 3) main 有点特殊功能。我想知道argcargv 是否与这些额外的8 个字节有关(尽管它们是参数,应该用ebp+... 访问)
  • 另外,您使用的是什么编译器?编译行是什么?
  • 您的编译器只是碰巧将变量放置在与本书作者使用的编译器不同的堆栈偏移处。这不应该让人感到意外——不同的编译器版本、选项、操作系统、配置选择等可能会导致这些事情发生变化。造成这种情况的确切原因很复杂,但对于理解您的实际应用程序代码的工作方式并不重要。

标签: assembly gcc x86


【解决方案1】:

sub esp,0x10

在堆栈上为变量和其他东西分配了 16 字节(相当于四个寄存器)的空间。

mov DWORD PTR [ebp-0xc],0x0

似乎是对插槽ebp-0xc 的第一个引用,并且它被初始化为零。在main+60 查看cmp DWORD PTR [ebp-0xc],0x9 之后,我确定这是for 循环的初始化部分中的i = 0

编译器可以将变量放在它想要的位置,并且在确定性的同时它会随着编译器的补丁版本而改变。

【讨论】:

  • 值得一提的是,它保留了更多的堆栈空间来维护/恢复 call puts 之前的 16 字节堆栈对齐,和/或保存 EBX,因为在 OP 的 GCC 版本中默认启用了 -fPIE -pie . call 0x4010a0 &lt;__x86.get_pc_thunk.bx&gt; 也不会出现在书中 - 这是位置无关代码的标志,在 32 位模式下效率低下。
  • Compiling C to 32-bit assembly with GCC doesn't match a book 是另一本书,但有一些关于 lea ecx,[esp+0x4] / and 对齐 ESP 和 __x86.get_pc_thunk 的细节。
  • 关于这本书的一般问答:"Hacking: The Art of Exploitation" - Assembly Inconsistencies in book examples vs. my system's gcc"Art of Exploitation" disassembly example isn't the same (C code) 是同一本书中的特定代码,但使用 AT&T 语法。答案是不同的,所以我不愿意在任一方向关闭为重复项。 (虽然这个问题不太具体。)
  • 感谢所有链接。我的目标不是试图产生完全相同的汇编输出,而是真正了解数据是如何存储在内存中的,并按照书中所示的方式获取它们。在上面,@Nate Eldredge 的回答帮助我理解了新版本的汇编输出,并且我确实从内存中检索到了我正在寻找的字符串。这就是我问这个问题的真正原因。再次感谢。
猜你喜欢
  • 2022-01-23
  • 2019-01-12
  • 1970-01-01
  • 2012-01-31
  • 2014-08-14
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多