2016-08-05 56 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