解析手順

■ 静的解析

まずは逆アセンブル結果と,実行ファイルの解析結果を見てみます.
% 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
%

■ 文字列のアドレス特定

Exploitのために,たとえば「ls」という文字列へのポインタを渡す必要があります.

以下の手順で探せます.

  1. 実行ファイルをバイナリエディタで開き,実行ファイル中の「ls」という文字列が ある場所を検索する.(ヌルターミネートされていなければならないので, 0x6c 0x73 0x00 みたいな3バイト列を探す)

  2. ヒットした場所のオフセット値(ファイル先頭をゼロとしたときの位置)を見る.

  3. readelf -a <実行ファイル> の出力結果のセクション情報と, ヒットした文字列のオフセット値を照らし合わせて,ヒットした文字列が どのセクションに含まれているか調べる.たとえば.rodataセクションが 以下のようになっているならば,.rodataセクションはファイル先頭から 0x025a60の位置を先頭として,サイズ0x003e61ぶんが割り当てられている. 文字列のオフセット値がその範囲内にあるのか調べる.
    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に戻って調べ直す.

  4. readelfの結果から,セクションの先頭のファイル先頭からのオフセット値と, セクションが配置されるアドレスを調べる. 例えば文字列が.rodataセクションに配置されていて,readelf で得た .rodataセクションの情報が以下のようになっていたとする.
    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による解析結果から知ることができる. 例えば以下は call_exec() が配置されているアドレス.
% readelf -a calendar | grep call_exec
  1634: 08048540    35 FUNC    GLOBAL DEFAULT    2 call_exec
%

■ アセンブラを読む

まずはobjdumpによる逆アセンブル出力を見てみます.
% 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
以下をポイントにして読むといいでしょう. こんな感じで読んでいくと,どの変数がスタック上のどの位置に配置されているのかが わかります.