为什么下面的程序在执行时不会崩溃,而是在GDB中发生段错误? 用GCC 4.5.2在32位x86(Athlon 64,如果应该的话)编译。
#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("%p\n", &argc); return 0; }