g++4.8的堆栈内容

Stack content for g++4.8

本文关键字:栈内容 堆栈 g++4      更新时间:2023-10-16

我写了一段简单的代码来测试缓冲区溢出:

#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(g++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$
  • 接下来的两个单词是什么

要查看调用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 <strcpy@plt>
   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-由0x000000000040052d <+0>: push %rbp推送到堆栈上
  3. 接下来的4个值通过0x0000000000400531 <+4>: sub $0x20,%rsp
  4. 您可以看到参数23在调用strcpy之前保存在堆栈上(0x0000000200000003-因为int只有4字节长)

您还可以从反汇编中推导出堆栈上的其他值。

堆栈的顶部在开头(地址0x7fffffffddb0),地址变大(例如第三行的0x7fffffffddd0),因此您可以看到堆栈确实向下增长,但gdb显示为上下颠倒。