現在、Hacking:The Art of ExploitationをJon Ericksonが読んでいます。私はマシンと32ビットと64ビットシステムの違いを研究するように強制して、本書で提供されているバーチャルマシンではなく、x64 Ubuntu 16.04.2システムのエクササイズに従っています。私は現在、本の冒頭に向かっており、スタックフレームアセンブリについて学んでいますが、これを自分のマシンで実行したときの結果については混乱していました。コードをコンパイルするためにGCCを使用する場合:スタックフレームの道を見ることがtest_functionにブレークポイントを設定するには、GDBを使用したスタックフレームアセンブリ - バッファ/ガベージスペースとスタック上の引数の場所 - Ubuntu x64
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 <[email protected]>
0x0000000000400589 <+67>: leave
0x000000000040058a <+68>: ret
が、私はメモリを見て:
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);
}
私は、アセンブリを与えられています建設された。
(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
私の質問保存されたフレームポインタが0x7fffffffde10でありながら、なぜ0x7fffffffdddfを介してメモリアドレス0x7fffffffddd0に配置された関数への引数でされており、リターンアドレスは0x7fffffffde18にあります。私は、これらの値がメモリ内にお互いにすぐ隣に格納されると思うでしょうが、何らかの理由でコンパイラが完全な64ビットの引数を格納します。
最初は私はこれが整列の問題かもしれないと思っていました。空きスペースはバッファスペースかもしれませんが、私がオンラインで集めたものから、メモリは64ビットではなく16ビット間隔で整列する傾向があります。メモリが16ビット間隔で整列されている場合、0x7fffffffde00〜0x7fffffffde0fに引数が格納されないのはなぜですか?
さらに、リターンアドレスとパラメータの間のスペースには意味がありますか、それともちょうど迷惑データですか? 0x7fffffffdde8、0x7fffffffde00、0x7fffffffde08の値は、メモリのテキストセグメントのメモリアドレスと思われるため、少し面白いようですが、スタックの一般的に使用されているセグメントにバッファスペースを割り当てることの結果である可能性もあります。
語るので、コンパイラは賢明な何かをしようとしません。それは単なる便利なところにものを置くだけです。 –