为什么下面的程序在执行时没有崩溃,而是在GDB中崩溃并出现段错误?在 32 位 x86(Athlon 64,如果重要的话)上使用 GCC 4.5.2 编译。
#include <stdio.h>
#include <string.h>
int modify(void)
{
__asm__("mov $0x41414141, %edx"); // Stray value.
__asm__("mov $0xbffff2d4, %eax"); // Addr. of ret pointer for function().
__asm__("mov %edx, (%eax)");
}
int function(void)
{
modify();
return 0;
}
int main(int argc, char **argv)
{
function();
return 0;
}
mov $0xbffff2d4, %eax 是使用 GDB 确定的,以查找存储"函数"函数的返回指针的地址。在不同的系统上,这可能会有所不同。ASLR 因此被禁用。
当我执行程序时,没有任何反应。也没有关于dmesg崩溃的报告。但是,当我在 GDB 中执行相同的程序时:
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
=> 0x41414141: Cannot access memory at address 0x41414141
这也是我正常执行程序时所期望的。当其他程序崩溃时,我确实像往常一样出现段错误,并且我可以轻松地编写一个以很好的段错误崩溃的小程序。但是为什么这个特定的程序不会因段错误而崩溃?
即使禁用了完全 ASLR,您仍然可能会获得随机堆栈和堆。您可以使用norandmaps
内核引导参数全局关闭它,也可以在运行时通过将/proc/sys/kernel/randomize_va_space
设置为零来关闭它。这也是过程个性的一部分。
在 GDB 中,您可以使用disable-randomization
设置进行调整:
(gdb) help set disable-randomization
Set disabling of debuggee's virtual address space randomization.
When this mode is on (which is the default), randomization of the virtual
address space is disabled. Standalone programs run with the randomization
enabled by default on some platforms.
作为一个小型测试程序来说明这一点,您可以打印局部变量的地址,例如:
#include <stdio.h>
int main(int argc, char **argv)
{
printf("%pn", &argc);
return 0;
}