% readelf -a calendar (実行ファイルの解析結果) % objdump -x calendar (実行ファイルの解析結果) % hexdump -C calendar (実行ファイルのバイナリダンプ) % objdump -d calendar (実行ファイルの逆アセンブル結果)bof-sample-1.1以降では,analyzeというディレクトリに上記コマンドを実施した際の 出力結果があらかじめ格納してあります.とりあえずそれを見てみるといいでしょう.
% cd bof-sample/FreeBSD/analyze % ls Makefile disasm.out objdump.out analyze.txt hexdump.out readelf.out %
以下の手順で探せます.
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al ... [ 4] .rodata PROGBITS 0806da60 025a60 003e61 00 A 0 0 32文字列が配置されているのが .text や .rodata セクションならば,問題無い. それ以外のセクションの場合なら,メモリ上にロードされなかったり値が変更 されたりする可能性があり適切でないので,1に戻って調べ直す.
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al ... [ 4] .rodata PROGBITS 0806da60 025a60 003e61 00 A 0 0 32この場合,.rodataセクションは実行ファイルの先頭から 0x025a60 の位置から 配置されていて,さらにメモリ上に配置されるときは0x0806da60というアドレスに ロードされる.よって文字列が配置されるアドレスは,以下のような計算で 求めることができる.
<文字列のオフセット値> - 0x025a60 + 0x0806da60 → <文字列のアドレス>
% readelf -a calendar | grep call_exec 1634: 08048540 35 FUNC GLOBAL DEFAULT 2 call_exec %
% objdump -d calendar | less例えばcheck_password()の先頭を探すと,以下のような部分があります.
08048320 <check_password>: 8048320: 83 ec 3c sub $0x3c,%esp 8048323: c7 44 24 30 00 00 00 movl $0x0,0x30(%esp) 804832a: 00 804832b: c7 44 24 34 1d db 06 movl $0x806db1d,0x34(%esp) 8048332: 08 8048333: 8d 44 24 20 lea 0x20(%esp),%eax 8048337: 89 44 24 04 mov %eax,0x4(%esp) 804833b: c7 04 24 21 db 06 08 movl $0x806db21,(%esp) 8048342: e8 79 01 00 00 call 80484c0 <input> 8048347: 89 44 24 38 mov %eax,0x38(%esp) 804834b: 8b 44 24 44 mov 0x44(%esp),%eax 804834f: 89 44 24 08 mov %eax,0x8(%esp) 8048353: 8b 44 24 38 mov 0x38(%esp),%eax 8048357: 89 44 24 04 mov %eax,0x4(%esp) 804835b: 8d 44 24 20 lea 0x20(%esp),%eax 804835f: 89 04 24 mov %eax,(%esp) 8048362: e8 c9 00 00 00 call 8048430 <check_string> 8048367: 85 c0 test %eax,%eax 8048369: 74 2d je 8048398 <check_password+0x78> 804836b: a1 c8 2c 07 08 mov 0x8072cc8,%eax 8048370: 89 44 24 0c mov %eax,0xc(%esp) ... 8048412: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048419: e8 72 00 00 00 call 8048490 <puts_flush> 804841e: 8b 44 24 34 mov 0x34(%esp),%eax 8048422: 89 04 24 mov %eax,(%esp) 8048425: e8 46 01 00 00 call 8048570 <command_exec> 804842a: 83 c4 3c add $0x3c,%esp 804842d: c3 ret 804842e: 89 f6 mov %esi,%esi以下をポイントにして読むといいでしょう.
8048342: e8 79 01 00 00 call 80484c0 <input>
8048333: 8d 44 24 20 lea 0x20(%esp),%eax 8048337: 89 44 24 04 mov %eax,0x4(%esp) 804833b: c7 04 24 21 db 06 08 movl $0x806db21,(%esp) 8048342: e8 79 01 00 00 call 80484c0 <input>これはC言語のソースコード(calendar.c)では,check_password()内で行われて いる以下の関数呼び出しに相当する.
len = input("Password: ", buffer); /* パスワードを入力(ここに脆弱性がある) */input()の呼び出し前に,input()に渡す引数を用意している. 具体的にはスタックポインタ+0x20の値(バッファのアドレス)を第2引数に, 0x806db21 という値("Password: "という文字列へのポインタ)を第1引数として スタック上に格納している.
8048342: e8 79 01 00 00 call 80484c0 <input> 8048347: 89 44 24 38 mov %eax,0x38(%esp)input()からの戻り値をスタックポインタ+0x38の位置に格納している. これはC言語ソースコードを見ると,戻り値を変数lenに格納している 処理だと検討がつく.つまり変数lenはスタックポインタ+0x38の位置にある.