2014-03-27 84 views
3

我明白「堆棧粉碎檢測」是什麼意思。這裏已經有很多問題了。但是我沒有找到以下問題的答案。就拿C代碼爲什麼粉碎後不立即出現「檢測到堆棧粉碎」?

int main(int argc, char **args) { 
    char puffer[5]; 
    strcpy(puffer, *++args); 
    printf("%s\n",puffer); 
    return EXIT_SUCCESS; 
} 

當我在Ubuntu 13.10與GCC 4.8.1編譯./buffer 123456789引發預期的錯誤stack smashing detected。但爲什麼./buffer 12345678沒有提出錯誤?我期望每個字符串超過5個字符都會引發錯誤。

+0

你實際上可能需要'-fmudflap'或Valgrind。 –

回答

4

理論上你是對的,那就是它應該如何表現。當你的程序使用超過5個字節時,這可能導致未定義的行爲。但由於各種性能原因,堆棧指針通常爲aligned to certain boundaries。從架構到架構的對齊方式各不相同。因此,對於每個大於5的輸入,您都不會看到此問題。

程序的反彙編顯示如下。檢查sub $0x20,%rsp指令,該指令在堆棧中爲此功能分配16個字節的內存。

(gdb) disassemble main 
Dump of assembler code for function main(int, char**): 
    0x00000000004008b0 <+0>: push %rbp 
    0x00000000004008b1 <+1>: mov %rsp,%rbp 
=> 0x00000000004008b4 <+4>: sub $0x20,%rsp 
    0x00000000004008b8 <+8>: mov %edi,-0x14(%rbp) 
    0x00000000004008bb <+11>: mov %rsi,-0x20(%rbp) 
    0x00000000004008bf <+15>: mov %fs:0x28,%rax 
    0x00000000004008c8 <+24>: mov %rax,-0x8(%rbp) 
    0x00000000004008cc <+28>: xor %eax,%eax 
    0x00000000004008ce <+30>: addq $0x8,-0x20(%rbp) 
    0x00000000004008d3 <+35>: mov -0x20(%rbp),%rax 
    0x00000000004008d7 <+39>: mov (%rax),%rdx 
    0x00000000004008da <+42>: lea -0x10(%rbp),%rax 
    0x00000000004008de <+46>: mov %rdx,%rsi 
    0x00000000004008e1 <+49>: mov %rax,%rdi 
    0x00000000004008e4 <+52>: callq 0x400770 <[email protected]> 
    0x00000000004008e9 <+57>: lea -0x10(%rbp),%rax 
    0x00000000004008ed <+61>: mov %rax,%rdi 
    0x00000000004008f0 <+64>: callq 0x400710 <[email protected]> 
    0x00000000004008f5 <+69>: mov $0x0,%eax 
    0x00000000004008fa <+74>: mov -0x8(%rbp),%rcx 
    0x00000000004008fe <+78>: xor %fs:0x28,%rcx 
    0x0000000000400907 <+87>: je  0x400918 <main(int, char**)+104> 
    0x0000000000400909 <+89>: jmp 0x400913 <main(int, char**)+99> 
    0x000000000040090b <+91>: mov %rax,%rdi 
    0x000000000040090e <+94>: callq 0x400790 <[email protected]> 
    0x0000000000400913 <+99>: callq 0x400760 <[email protected]> 
    0x0000000000400918 <+104>: leaveq 
    0x0000000000400919 <+105>: retq 
+0

是的,SSE2指令的16字節堆棧對齊。 –

2

編譯器實現了不同的堆棧粉碎保護措施,但通常是爲了防止堆棧溢出,將金絲雀放在保存的幀指針和返回地址之前。金絲雀在這裏保護覆蓋保存的幀指針和返回地址。這裏基本上是由編譯器在緩衝區的末尾和幀指針/返回地址之間插入一些填充。