主函数之前的EBP值重要吗?

逆向工程 x86 记忆 缓冲区溢出 登记
2021-06-28 11:39:54

所以在我们来到 main 函数之前,看起来我们在一个名为 __libc_start_main 的函数中

在我们来到我们的主函数之前,我们显然将 EBP 值压入堆栈(主函数之前的 EBP 值,在 __libc_start_main 函数中)

所以首先这个值重要吗?main函数执行后,__libc_start_main函数需要这个值吗?

是否有任何函数在 __libc_start_main 之前被调用,因此使这个 EBP 值很重要?

我测试了它,即使我用溢出覆盖了这个值(在堆栈中),程序完成没有问题,但我不明白如何以及为什么?它不应该导致错误或页面错误吗?

1个回答

__libc_start_main入口点代码调用(通常在名为crt0.S或类似的文件中)并且代码通常设置初始EBP值(通常为 0,以表示调试器的调用堆栈结束)。这是来自随机 ELF 二进制文件的示例入口点代码:

_start:
     xor     ebp, ebp
     pop     esi
     mov     ecx, esp
     and     esp, 0FFFFFFF0h
     push    eax
     push    esp             ; stack_end
     push    edx             ; rtld_fini
     push    offset __libc_csu_fini ; fini
     push    offset __libc_csu_init ; init
     push    ecx             ; ubp_av
     push    esi             ; argc
     push    offset main     ; main
     call    ___libc_start_main
     hlt

虽然__libc_start_main它本身可以初始化EBP为 0,但在查看调用堆栈时,这会使它看起来好像是二进制文件中的第一个代码,这是不正确的(执行从_start入口点开始)。

此外,__libc_start_main 可以(并且经常是)用 C 语言而不是汇编语言编写,并且编译器更容易为它生成标准的 prolog 代码,而不是产生某种特殊情况的异常。

至于覆盖该值,您不会崩溃,因为:

  1. ebp___libc_start_main(入口点代码)的调用者实际上并未使用
  2. ___libc_start_main实际上并没有返回,因为它调用exit()返回值main()to 直接退出到操作系统,所以你的损坏ebp没有关系

在不太可能___libc_start_main返回的情况下(例如,由于 libc 中的错误),入口点代码将执行hlt特权指令,因此该进程将被操作系统杀死。