GDB & Virtual Address
22252 ワード
GDB & Virtual Address
仮想メモリの概念をより明確に理解するために、GDBの実践を通じて、実際の仮想メモリにおけるグローバル変数と領域変数の位置を理解します.32ビットコンピュータに基づいています.
>> docker pull tomerbd/gcc-gdb-dockerfile
>> docker run -it -v $(pwd):/src \
--security-opt seccomp=unconfined \
tomerbd/gcc-gdb-dockerfile \
/bin/bash
--security-opt seccomp=unconfined
が与えられた場合、gdb動作はアドレス空間ランダム化を生じない.#include <stdlib.h>
int main() {
int a = 0xBEEF;
int *b = malloc(sizeof(int));
g = 0xDDDD;
return 0;
}
上記のコードを実行可能オブジェクトファイルにコンパイルし、gdbを使用します.root@8c32719ecb7c:~# gcc main.c
root@8c32719ecb7c:~# ls
a.out main.c
root@8c32719ecb7c:~# gdb a.out
(gdb) disas main
Dump of assembler code for function main:
0x000000000040052d <+0>: push %rbp
0x000000000040052e <+1>: mov %rsp,%rbp
0x0000000000400531 <+4>: sub $0x10,%rsp
0x0000000000400535 <+8>: movl $0xbeef,-0x10(%rbp)
0x000000000040053c <+15>: mov $0x4,%edi
0x0000000000400541 <+20>: callq 0x400430 <malloc@plt>
0x0000000000400546 <+25>: mov %rax,-0x8(%rbp)
0x000000000040054a <+29>: movl $0xdddd,-0xc(%rbp)
0x0000000000400551 <+36>: mov $0x0,%eax
0x0000000000400556 <+41>: leaveq
0x0000000000400557 <+42>: retq
End of assembler dump.
コンポーネントを確認できます.gdbコマンドdisas
は、コードの周囲の構築を確認することができ、disas main
は、仮想メモリ内のプライマリ関数構築を確認することができる.まずInstruction第1部0x000000000040052d <+0>: push %rbp
を見てみましょうここでは、仮想メモリ上のコード領域の開始位置です.上の図では、Read-onlyセグメントは、例では0 x 40052 dのアドレスを持つコードの開始部分であり、理論的にはコード位置0 x 40054 s付近に位置する.これにより、ギジェコードが理論に従って仮想メモリに位置することを確保できます.
ここの
0xBEEF
のaの住所はどこですか?(gdb) break *0x000000000040053c
Breakpoint 1 at 0x40053c
(gdb) run
Starting program: /root/a.out
Breakpoint 1, 0x000000000040053c in main ()
(gdb)
(gdb) disas
Dump of assembler code for function main:
0x000000000040052d <+0>: push %rbp
0x000000000040052e <+1>: mov %rsp,%rbp
0x0000000000400531 <+4>: sub $0x10,%rsp
0x0000000000400535 <+8>: movl $0xbeef,-0x10(%rbp)
=> 0x000000000040053c <+15>: mov $0x4,%edi
0x0000000000400541 <+20>: callq 0x400430 <malloc@plt>
0x0000000000400546 <+25>: mov %rax,-0x8(%rbp)
0x000000000040054a <+29>: movl $0xdddd,-0xc(%rbp)
0x0000000000400551 <+36>: mov $0x0,%eax
0x0000000000400556 <+41>: leaveq
0x0000000000400557 <+42>: retq
End of assembler dump.
次のコンストラクションmovl
、次のコンストラクションmov
では、プログラムを中断的に開始しました.movl src dest
の構成は、srcからdestにコピーされた4バイトを表す.$0xbeef
はこの値を表し、movl $0xbeef,-0x10(%rbp)
は-0x10(%rbp)
を$0xbeef
にコピーすることを表す.したがって、-0x10(%rbp)
は変数aのアドレスである.(gdb) x/2xb $rbp-0x10
0x7fffffffe700: 0xef 0xbe
x
はgdbの「チェック」コマンドで、メモリの値を表示します.x
コマンドの使用方法については、次のリンクを参照してください.gdbのxを使用して仮想アドレスを表示する
$rbp-0x10
はrbpのrbp 레지스터에 들어있는 값 -0x10
を表し、仮想メモリアドレスを表す.rbp
レジスタに含まれる値がどれくらいなのかを見て、実際の状況を理解しましょう.(gdb) p $rbp
$1 = (void *) 0x7fffffffe710
rbpはアドレス0x7fffffffe710
を含む.これは、アドレスから0x10
を減算したアドレスに0 xbeef値が含まれていることを意味しますよね?メモリアドレス値を入力して検証しましょう.(gdb) x/2x 0x7fffffffe700
0x7fffffffe700: 0xef 0xbe
0 xefと0 xbeの値を確認できます.興味深いことに、表示される値は順番ではなく、バイト順に並べられています.理由は
little endian
の概念に基づいている.アドレス0x7fffffffe700
は0 xefバイト値を含み、アドレス0x7fffffffe701
は0 xbeバイト値を含む.Little endianは、メモリにデータを格納するときにless signigantバイト値を最初に格納する方法です.この部分は別の文章でさらに議論される.(gdb) x/xw 0x7fffffffe700
0x7fffffffe700: 0x0000beef
字単位で読むと0x0000beef
が見えます.次に、malloc
関数を呼び出し、HipMemoryアドレスを受信した整数ポインタ変数b
の値を調べ、HipMemoryアドレスの位置を決定する.(gdb) break *0x000000000040054a
Breakpoint 2 at 0x40054a
(gdb) cont
Continuing.
Breakpoint 2, 0x000000000040054a in main ()
(gdb)
(gdb) disas
Dump of assembler code for function main:
0x000000000040052d <+0>: push %rbp
0x000000000040052e <+1>: mov %rsp,%rbp
0x0000000000400531 <+4>: sub $0x10,%rsp
0x0000000000400535 <+8>: movl $0xbeef,-0x10(%rbp)
0x000000000040053c <+15>: mov $0x4,%edi
0x0000000000400541 <+20>: callq 0x400430 <malloc@plt>
0x0000000000400546 <+25>: mov %rax,-0x8(%rbp)
=> 0x000000000040054a <+29>: movl $0xdddd,-0xc(%rbp)
0x0000000000400551 <+36>: mov $0x0,%eax
0x0000000000400556 <+41>: leaveq
0x0000000000400557 <+42>: retq
End of assembler dump.
%rax
レジスタは、malloc関数を呼び出す例を示す戻り値を格納するレジスタであるため、%rax
レジスタにhipメモリアドレス値が含まれることが予想される.(gdb) p/x $rax
$4 = 0x602010
%rax
レジスタの値は16進数で検証され、0x602010
と決定される.この値はHip Memoryの開始アドレスです.では、ポインタ変数b
を格納する位置はどこですか?0x0000000000400546 <+25>: mov %rax,-0x8(%rbp)
では、%rax
のレジスタ値がアドレス-0x8(%rbp)
に格納されていることがわかります.もしそうであれば、アドレスはbの位置であり、私たちが前に見た0x602010
が格納されている可能性があります.確認してみましょう.(gdb) x/xw $rbp-0x8
0x7fffffffe708: 0x00602010
1つずつ読みます(gdb) x/4xb $rbp-0x8
0x7fffffffe708: 0x10 0x20 0x60 0x00
値が含まれていることを確認します.Heapメモリも仮想メモリの低い位置にあります.また、stackとしての領域変数bのアドレス値は非常に大きい(0x7fffffffe708
).仮想メモリマップに示すように、code、heap、stackの位置を決定できます.今回は、グローバル変数がdataに存在するかどうかを決定するために、コードをいくつか変更します.
#include <stdlib.h>
int g = 0xDEAD;
int main() {
int a = 0xBEEF;
g = 0xDDDD;
return 0;
}
以上のコードをコンパイルしgdbを実行します.(gdb) disas main
Dump of assembler code for function main:
0x00000000004004ed <+0>: push %rbp
0x00000000004004ee <+1>: mov %rsp,%rbp
0x00000000004004f1 <+4>: movl $0xbeef,-0x4(%rbp)
0x00000000004004f8 <+11>: movl $0xdddd,0x200b36(%rip) # 0x601038 <g>
0x0000000000400502 <+21>: mov $0x0,%eax
0x0000000000400507 <+26>: pop %rbp
0x0000000000400508 <+27>: retq
End of assembler dump.
(gdb) break *0x0000000000400502
Breakpoint 1 at 0x400502
(gdb) run
Starting program: /root/a.out
Breakpoint 1, 0x0000000000400502 in main ()
(gdb)
(gdb) disas
Dump of assembler code for function main:
0x00000000004004ed <+0>: push %rbp
0x00000000004004ee <+1>: mov %rsp,%rbp
0x00000000004004f1 <+4>: movl $0xbeef,-0x4(%rbp)
0x00000000004004f8 <+11>: movl $0xdddd,0x200b36(%rip) # 0x601038 <g>
=> 0x0000000000400502 <+21>: mov $0x0,%eax
0x0000000000400507 <+26>: pop %rbp
0x0000000000400508 <+27>: retq
End of assembler dump.
上記のコンポーネントコードでは、$0 xdddを特定のアドレスにコピーしています.その位置はグローバル変数0x200b36(%rip)
に等しい(gdb) x/2xb $rip+0x200b36
0x601038 <g>: 0xdd 0xdd
対応するアドレス値を読み込むと、0 xddと0 xddを確認できます.今度は単語単位で読みましょう(gdb) x/xw $rip+0x200b36
0x601038 <g>: 0x0000dddd
文字単位で読み取っても正常に読み取れます.上のコンポーネントコードをよく見てください.g
0x00000000004004f8 <+11>: movl $0xdddd,0x200b36(%rip) # 0x601038 <g>
が表示されます.gというグローバル変数の位置は、コンポーネントコードにおいて0 x 601038と決定され得る.上の# 0x601038 <g>
も同じアドレスを指しています.さらに、$rip+0x200b36
は、コード開始点0x601038
の後に位置し、これは、仮想メモリ上のデータ部分がコード部分の後よりもアドレス上にあることを示す.仮想メモリにおけるコード,データ,スタック,スタック部分の理論的位置を検証した.Reference
この問題について(GDB & Virtual Address), 我々は、より多くの情報をここで見つけました https://velog.io/@suseodd/GDB-Virtual-Addressテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol