堆栈框架程序集 - 缓冲区/垃圾空间和堆栈中参数的位置 - Ubuntu x64

时间:2017-05-30 03:46:55

标签: c assembly memory stack allocation

我目前正在阅读Jon Erickson的“黑客:剥削艺术”一书。我正在跟随x64 Ubuntu 16.04.2系统上的练习,而不是本书提供的虚拟机,试图通过强迫我研究机器,32位和64位系统之间的差异来加强我的理解。我目前正在阅读本书的开头部分,并了解堆栈框架组装,但我对在机器上运行时获得的结果感到困惑。使用GCC编译代码时:

void test_function(int a, int b, int c, int d) {
  int flag;
  char buffer[10];

  flag = 31337;
  buffer[0] = 'A';
}

int main() {
  test_function(1, 2, 3, 4);
}

我得到了集会:

 Dump of assembler code for function main:
   0x000000000040058b <+0>:     push   rbp
   0x000000000040058c <+1>:     mov    rbp,rsp
   0x000000000040058f <+4>:     mov    ecx,0x4
   0x0000000000400594 <+9>:     mov    edx,0x3
   0x0000000000400599 <+14>:    mov    esi,0x2
   0x000000000040059e <+19>:    mov    edi,0x1
   0x00000000004005a3 <+24>:    call   0x400546 <test_function>
   0x00000000004005a8 <+29>:    mov    eax,0x0
   0x00000000004005ad <+34>:    pop    rbp
   0x00000000004005ae <+35>:    ret   

Dump of assembler code for function test_function:
   0x0000000000400546 <+0>:     push   rbp
   0x0000000000400547 <+1>:     mov    rbp,rsp
   0x000000000040054a <+4>:     sub    rsp,0x40
   0x000000000040054e <+8>:     mov    DWORD PTR [rbp-0x34],edi
   0x0000000000400551 <+11>:    mov    DWORD PTR [rbp-0x38],esi
   0x0000000000400554 <+14>:    mov    DWORD PTR [rbp-0x3c],edx
   0x0000000000400557 <+17>:    mov    DWORD PTR [rbp-0x40],ecx
   0x000000000040055a <+20>:    mov    rax,QWORD PTR fs:0x28
   0x0000000000400563 <+29>:    mov    QWORD PTR [rbp-0x8],rax
   0x0000000000400567 <+33>:    xor    eax,eax
   0x0000000000400569 <+35>:    mov    DWORD PTR [rbp-0x24],0x7a69
   0x0000000000400570 <+42>:    mov    BYTE PTR [rbp-0x20],0x41
   0x0000000000400574 <+46>:    nop
   0x0000000000400575 <+47>:    mov    rax,QWORD PTR [rbp-0x8]
   0x0000000000400579 <+51>:    xor    rax,QWORD PTR fs:0x28
   0x0000000000400582 <+60>:    je     0x400589 <test_function+67>
   0x0000000000400584 <+62>:    call   0x400420 <__stack_chk_fail@plt>
   0x0000000000400589 <+67>:    leave  
   0x000000000040058a <+68>:    ret 

使用GDB在test_function上设置断点,我查看内存以查看堆栈帧的构造方式。

(gdb) x/20hw $rsp
0x7fffffffddd0: 0x00000004  0x00000003  0x00000002  0x00000001
0x7fffffffdde0: 0x00000001  0x00000000  0x004005fd  0x00000000
0x7fffffffddf0: 0x00000000  0x00000000  0x00000000  0x00000000
0x7fffffffde00: 0x004005b0  0x00000000  0x00400450  0x00000000
0x7fffffffde10: 0xffffde20  0x00007fff  0x004005a8  0x00000000

寄存器设置为:

(gdb) i r rip rsp rbp
rip            0x40055a 0x40055a <test_function+20>
rsp            0x7fffffffddd0   0x7fffffffddd0
rbp            0x7fffffffde10   0x7fffffffde10

我的问题是,为什么函数的参数位于内存地址0x7fffffffddd0到0x7ffffffddddf,而保存的帧指针位于0x7fffffffde10且返回地址位于0x7fffffffde18。我认为这些值将在内存中彼此相邻存储,但由于某种原因,编译器将参数存储在完整的64位之外。

最初我认为这可能是一个对齐问题,并且可用空间可能是缓冲区空间,但是从我在线收集的内容来看,内存往往以16位间隔对齐,而不是64位。如果内存以16位间隔对齐,那么为什么参数不存储在0x7fffffffde00到0x7fffffffde0f?

此外,返回地址和参数之间的空间是否有任何意义,或者这只是垃圾数据? 0x7fffffffdde8,0x7fffffffde00和0x7fffffffde08的值似乎有点有趣,因为它们似乎是内存文本段中的内存地址,但也有可能这是在堆栈的常用段上分配缓冲区空间的结果

1 个答案:

答案 0 :(得分:0)