2016-08-05 59 views
0

我寫了這個簡單的代碼進行測試緩衝區溢出:堆棧內容克++ 4.8

#include <stdio.h> 
#include <string.h> 
using namespace std; 
int f(int x, int y, char *s){ 
    char buf[4]; 
    strcpy(buf,s); 
    return 0; 
} 
int main(int argc, char** argv){ 
    f(2,3,argv[1]); 
    return 0; 
} 

然後編譯和用gdb觀看它的執行(克++ 4.8.4)

g++ -g -fno-stack-protector -o bo bo.c 
gdb bo 
... 
    b f 
    r "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 
    p $rbp // 0x7fffffffdc90 
    p $rsp // 0x7fffffffdc70 
    x/20xw $rsp 
    0x7fffffffdc70: 0xffffe0ef 0x00007fff 0x00000003 0x00000002 
    0x7fffffffdc80: 0xffffdcb0 0x00007fff 0x00000000 0x00000000 
    0x7fffffffdc90: 0xffffdcb0 0x00007fff 0x00400585 0x00000000 
    0x7fffffffdca0: 0xffffdd98 0x00007fff 0x00000000 0x00000002 
    0x7fffffffdcb0: 0x00000000 0x00000000 0xf7a36ec5 0x00007fff 

我的理解是堆棧向下增長爲到更低的地址,但它看起來這個堆棧幀(從0x7fffffffdc90 - 0x7fffffffdc90)向上增長:參數被向上推(s,y然後x)。這是爲什麼?

看起來像是先返回地址(0x00400585)。但接下來的話是什麼意思?他們是:

  • 已保存$rbp$
  • 接下來的2個單詞是什麼?
+0

您不是在使用Sys V AMD64 ABI嗎? –

+0

我該如何檢查? – user1734905

+1

不要混淆堆棧的管理方式(push/pop)如何處理GDB的表示; e * x * amine命令將始終按升序打印地址。 –

回答

2

要查看f調用後會發生什麼你的籌碼,調用在gdb反彙編:

(gdb) disas 
Dump of assembler code for function f(int, int, char*): 
    0x000000000040052d <+0>: push %rbp 
    0x000000000040052e <+1>: mov %rsp,%rbp 
    0x0000000000400531 <+4>: sub $0x20,%rsp 
    0x0000000000400535 <+8>: mov %edi,-0x14(%rbp) 
    0x0000000000400538 <+11>: mov %esi,-0x18(%rbp) 
    0x000000000040053b <+14>: mov %rdx,-0x20(%rbp) 
    0x000000000040053f <+18>: mov -0x20(%rbp),%rdx 
    0x0000000000400543 <+22>: lea -0x10(%rbp),%rax 
    0x0000000000400547 <+26>: mov %rdx,%rsi 
    0x000000000040054a <+29>: mov %rax,%rdi 
=> 0x000000000040054d <+32>: callq 0x400410 <[email protected]> 
    0x0000000000400552 <+37>: mov $0x0,%eax 
    0x0000000000400557 <+42>: leaveq 
    0x0000000000400558 <+43>: retq 

調用strcpy堆棧樣子(我用的64位格式化,而不是32位)之前:

(gdb) x/6xg $rsp 
0x7fffffffddb0: 0x00007fffffffe297 0x0000000200000003 
0x7fffffffddc0: 0x00007fffffffddf0 0x0000000000000000 
0x7fffffffddd0: 0x00007fffffffddf0 0x0000000000400585 

所以你可以看到:

  1. 0x0000000000400585 - 函數返回地址f
  2. 就在旁邊0x00007fffffffddf0 - 通過 0x0000000000400531 <+4>: sub $0x20,%rsp
  3. 壓入堆棧由0x000000000040052d <+0>: push %rbp
  4. 在接下來的4個值在堆棧上保留你可以看到參數23被保存之前的調用堆棧上strcpy0x0000000200000003 - 因爲int只有4個字節長)。

您也可以從反彙編中推斷堆棧中的其他值。

堆棧頂端位於開頭(地址爲0x7fffffffddb0),地址變大(例如第三行爲0x7fffffffddd0),所以您可以看到堆棧確實向下增長,但是由gdb反轉顯示。

+0

在返回的地址之前不會推送參數?爲什麼這個gdb顯示顛倒的地址? – user1734905

+1

@ user1734905它是Sys V AMD64 ABI,所以參數在寄存器'edi','esi'和'rdx'中。在調用'strcpy'之前必須將它們保存到堆棧,否則這些值可能會丟失。你沒有優化,所以編譯器不關心,你以後不需要這些值,並保存它們。 – ead