C缓冲区溢出 – 为什么有一个固定的字节数会导致段错误? (Mac OS 10.8 64位,铿锵)

我在C中试验缓冲区溢出,发现了一个有趣的怪癖:

对于任何给定的数组大小,似乎有一定数量的溢出字节可以在SIGABRT崩溃之前写入内存。 例如,在下面的代码中,10字节数组可以在27处崩溃之前溢出到26个字节。类似地,在第41个char中止之前,20个char的数组可以溢出到40个char

谁能解释为什么会这样? 此外,SIGABRT是否与“分段故障”相同(或由其引起)?

Mac OS 10.8 – Xcode 4.6,clang和lldb。 谢谢!

 #include  int main(int argc, const char * argv[]) { char aString[ 10 ]; char aLetter = 'a'; printf("The size of one array slot sizeof( aString[0] ) is %zu\n", sizeof(aString[0])); printf("The size of one letter sizeof( aLetter ) is %zu\n", sizeof(aLetter)); // Overflow the aString array of chars // lldb claims aString is initialized with values \0 or NULL at all locations // Substitute i<27 and this code will crash regularly for (int i=0; i<26; i++) { aString[i]= aLetter; } return 0; } 

编辑 – 我在反汇编中逐步完成了它,并在for循环之后发现了这种保护:

 0x100000f27: movq 226(%rip), %rax ; (void *)0x00007fff793f24b0: __stack_chk_guard 0x100000f2e: movq (%rax), %rax 0x100000f31: movq -8(%rbp), %rcx 0x100000f35: cmpq %rcx, %rax 0x100000f38: jne 0x100000f49 ; main + 121 at main.c:26 . . . 0x100000f49: callq 0x100000f4e ; symbol stub for: __stack_chk_fail 

这是由于mac os上堆栈的对齐。

这不是一个大新闻,如果你用谷歌搜索它,你会找到答案:

为什么Mac ABI需要x86-32的16字节堆栈对齐?


很高兴看到你实际上可以写入堆栈,没有副作用小于16字节的块。

如果您多次使用它,您可以进入一个可以放置所有恶意代码的状态,并且可以在堆栈中跳转执行它。