x86逆コンパイルのすゝめ
アセンブリ記法
x86/x86-64アセンブリにはIntel記法とAT&T記法の2つの記法がある。
まずはIntel記法で学ぶことを奨める。AT&T記法はオペランドの順序が複雑であるためである。
Intel記法
広く利用されている形式で、特にWindowsで好んで利用される記法である。 操作対象のレジスタが必ず最初のオペランドになる。
objdumpによる逆アセンブル例
1 0000000000000000 <f>:
2 0: 55 push rbp
3 1: 48 89 e5 mov rbp,rsp
4 4: 48 83 ec 10 sub rsp,0x10
5 8: 89 7d fc mov DWORD PTR [rbp-0x4],edi
6 b: 83 7d fc 01 cmp DWORD PTR [rbp-0x4],0x1
7 f: 75 07 jne 18 <f+0x18>
8 11: b8 01 00 00 00 mov eax,0x1
9 16: eb 11 jmp 29 <f+0x29>
10 18: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
11 1b: 83 e8 01 sub eax,0x1
12 1e: 89 c7 mov edi,eax
13 20: e8 00 00 00 00 call 25 <f+0x25>
14 25: 0f af 45 fc imul eax,DWORD PTR [rbp-0x4]
15 29: c9 leave
16 2a: c3 ret
AT&T記法
Unix-likeな環境のスタンダードな形式である。 Intel記法とはオペランドの順序が逆順になる。
objdumpによる逆アセンブル例
1 0000000000000000 <f>:
2 0: 55 push %rbp
3 1: 48 89 e5 mov %rsp,%rbp
4 4: 48 83 ec 10 sub $0x10,%rsp
5 8: 89 7d fc mov %edi,-0x4(%rbp)
6 b: 83 7d fc 01 cmpl $0x1,-0x4(%rbp)
7 f: 75 07 jne 18 <f+0x18>
8 11: b8 01 00 00 00 mov $0x1,%eax
9 16: eb 11 jmp 29 <f+0x29>
10 18: 8b 45 fc mov -0x4(%rbp),%eax
11 1b: 83 e8 01 sub $0x1,%eax
12 1e: 89 c7 mov %eax,%edi
13 20: e8 00 00 00 00 callq 25 <f+0x25>
14 25: 0f af 45 fc imul -0x4(%rbp),%eax
15 29: c9 leaveq
16 2a: c3 retq
ツール
コマンドラインで利用できる逆アセンブラをいくつか紹介しておく。 まずはobjdumpを試し、手に馴染むものを探すと良い。
実行ファイル全般(elfでもPEでも)
- objdump (binutils project)
コード片(シェルコード)用
udcli (udis86 project)
Usage: CTF/Toolkit/udis86
ndisasm (nasm project)
- Intel形式のみ
Usage: CTF/Toolkit/ndisasm
Windowsの実行ファイル(PE)専用
- Intel形式のみ, 32bitのみ, 文字列埋め込みあり
- Intel形式のみ, 32bitのみ, フロー解析あり
- Windows用は単なる逆アセンブラよりも、インタラクティブなGUIのデバッガ兼逆アセンブラが豊富である。
objdump補助スクリプト
CTF/Toolkitのobjdumpの欄にobjdumpの使い勝手を改良するスクリプトをいくつか用意してある。
objdump
objdumpは逆アセンブルに限らず、各種オブジェクトファイルの情報を表示するツールである。 以下はオブジェクトファイルに含まれる情報の例である。
- ターゲットアーキテクチャ
- プログラムの開始アドレス(エントリポイント)
- セクションの開始位置とマップすべき仮想アドレス
- シンボル名
- 機械語
- プログラム中の文字列を含む定数
(objdumpによるオブジェクトファイルの情報抽出は別稿にて)
objdumpで逆アセンブルするには-dオプションを指定する。 Intel記法で逆アセンブルするには-M intelオプションを追加する必要がある。
$ objdump -d -M intel ./t ./t: file format elf64-x86-64 Disassembly of section .init: (略) Disassembly of section .plt: (略) Disassembly of section .text: (略) 000000000040051f <main>: 40051f: 55 push rbp 400520: 48 89 e5 mov rbp,rsp 400523: bf 0a 00 00 00 mov edi,0xa 400528: e8 c7 ff ff ff call 4004f4 <f> 40052d: 89 c2 mov edx,eax 40052f: b8 3c 06 40 00 mov eax,0x40063c 400534: 89 d6 mov esi,edx 400536: 48 89 c7 mov rdi,rax 400539: b8 00 00 00 00 mov eax,0x0 40053e: e8 ad fe ff ff call 4003f0 <printf@plt> 400543: 5d pop rbp 400544: c3 ret (略) Disassembly of section .fini: (略)
ABIを理解する
(以下執筆予定)
条件分岐命令を読む