【发布时间】:2020-01-29 20:27:42
【问题描述】:
我试图粉碎堆栈:
int main (void) {
int ar[5] = {1,2,3,4,5};
for(int i =0; i<255 ; i++)
ar[i] = 10;
return 0;
}
gcc -fno-stack-protector somefile.c。第一个问题:为什么(SIGABRT)和没有(SIGSEGV)保护器的故障存在差异,当两者都访问非法内存时(我认为应该有相同的故障)。
第二当objdump:
0000000000001125 <main>:
1125: 55 push %rbp
1126: 48 89 e5 mov %rsp,%rbp
1129: c7 45 e0 01 00 00 00 movl $0x1,-0x20(%rbp)
...
主地址的开头是虚拟0000000000001125
但是在没有保护器的情况下编译:
Program received signal SIGSEGV, Segmentation fault.
0x0000000af7be5b6b in ?? ()
地址(0x0000000af7be5b6b)是什么?虚拟的,物理的?我在反汇编文件中看不到它(如上所示),那么地址来自哪里?
编辑:
带保护器(因此有故障SIGABRT),我也不明白的输出:
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
__GI_raise 是什么宏?括号中的 sig=sig@entry=6 是什么,gcc 是否添加了故障表,或者链接器中的这些标记是什么?
【问题讨论】:
-
SIGABRT由一些检测违规的库函数发送(并且此检测是通过使用堆栈保护器启用的)。SIGSEGV由操作系统发送,当 它 检测到进程正在触摸它不应该触摸的东西。 -
而
SIGSEGV没有被任何库处理?还是内核中断器?两者在实现上有何不同? -
您尝试过完整的回溯吗?因为你不在主要你在“??”
-
对于普通进程和通用多用户操作系统,您在进程和调试器中看到的所有地址都是虚拟地址。除非您正在使用内核代码,包括一些设备驱动程序和类似的特权代码,否则您将看不到物理地址,或者已经进行了特殊安排。调试器不会报告物理地址,因为在您不可见的各种系统活动之后,程序中的相同虚拟地址可能会映射到不同的物理地址,因此物理地址通常不可用。
-
那为什么内核和设备驱动程序(或模块)需要访问物理地址呢?举一些特定(具体)的例子,内核在 IO 操作或启动模式下会使用物理地址端口吗?
标签: c stack buffer-overflow virtual-address-space stack-smash