我目前正在阅读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的值似乎有点有趣,因为它们似乎是内存文本段中的内存地址,但也有可能这是在堆栈的常用段上分配缓冲区空间的结果
答案 0 :(得分:0)