Macintoshは知りません。
いうてLinux,WindowsだってBinary得意なわけじゃない、いくらでもよくわかってないところがある。
Binary
あ、ものっそい今更だけど、僕はバイナリエディタはBZがおすすめだよ!
ReversingとPwnableがあります。
PwnableはReversingの上位だと思ってください。
Reversing
実行可能ファイルが与えられます。
どんな挙動をする実行可能ファイルかを読み解き、問題文に示されたことについて調査あるいはFLAGっぽいものを勘で探し当ててください。
What is 実行可能ファイル
a.out (アセンブラ アウトプット)
UNIXで昔使われてたらしい。僕は見たこと無い。
gccとかでコンパイルすると"a.out"という名前のファイルができるし、それが語源らしいけれど、しかし今のそれはこの形式ではない。
COFF (Common Object File Format)
オブジェクトファイルとか実行可能ファイルのフォーマット。特にPEファイルには色濃く受け継がれてるみたい。この辺の歴史がググっても出てこない。
ELF (Executable and Linkable Format)
今のLinuxはたぶんだいたいこれ。a.outってファイル名でもこれ。
objdump
nm
あたりを使うとよい。
http://softwaretechnique.jp/OS_Development/Tips/ELF/elf01.html
PE (Portable Executable)
COFFをMicrosoftが独自拡張した感じらしいので、PE/COFFとか呼ばれることもあり。
PEiDとかはよい。ただしこれ、昔しつこくアンチウィルスソフトに怒られたし、softpediaにあるあたり、あんまり信用しちゃいけない気もするけどね...
dumpbin、Microsoft製。VisualStudioについてたとおもう。
リソースを弄りたいときは、Resource Hacker。海外製ソフトを日本語化してる人は、こういうの使ってるげ。
Mach-O
しらない。強い人の追記希望。
ソフトウェアの動く仕組み
↑好き。まあ両方実家においてきちゃったみたいだから現物は貸せない。ごめんなさい。
ビルド
その手の本をちゃんと読んだわけでないので、ビルドとかコンパイルとかの定義を知らない。
コンパイル
- プリロセス - #include, #ifdefとか
- コンパイル - Cをアセンブリに
- アセンブル - アセンブリを機械語、オブジェクトファイルに
- 静的リンク - オブジェクトファイルをまとめて実行可能ファイルに
ローダ (Linux: ld-linux.so)
- ロード - ファイルを仮想メモリ上に
- 動的リンク - 読み込んだ仮想アドレスをもとに適当につじつまを合わせるよ
一応Linux - ELF、Windows - PE/COFFの間に何か関係があるわけではなくて、これらのフォーマットはコンテナみたいなものだから、機械語がアーキテクチャにあっていれば、ローダさえしっかり作ればたぶん動く。
WineとかBash on Ubuntu on Windowsとかってそんな感じなんじゃないのかな。(適当)
仮想メモリ
僕のパソコンはたぶん4GBのメモリが積んである。が、1プロセスには最低でも1GBのメモリが原理上使えるようになっている。
これには仮想メモリという技術が使われていて、仮想メモリ上のデータはすべては実メモリ上にのっていないし、複数プロセス間でメモリを共有したりいろいろしている。
(NetworkのときのNAPTが似ているかもしれない。ローカルIPアドレスが仮想メモリに対応しそう。)
実行可能ファイルの中には、機械語の領域とデータ領域が別れていて、それぞれが仮想メモリ上にマップされる。そのあとエントリポイントから実行が開始される。
実行
debugger tools
- IDA
- HT Editor
- objdump
- OllyDbg Windows, 32bit
- Immunity Debugger
- うさみみハリケーン Windows
- スペシャルねこまんま57号 Windows, 32bit?
- WinDbg Windows
- gdb
レジスタ
- EAX, EBX, ECX, EDX - なんでもデータが入る
- ESI, EDI - だいたいアドレスが入る
- ESP - スタックポインタ。スタックの先頭を常に指してる。
- EBP - ベースポインタ。今の関数内でのスタックへのアクセスの基点を示す。
- EIP - プログラムカウンタ。いま実行してる機械語の位置を常に指してる。
- EFLAGS - 演算結果の性質を表すフラグの集まり。
上はすべて32bit。EAXの下位16bitをAXとよび、AXの上位8bit,下位8bitをそれぞれAH,ALとよぶ。
x64になるとレジスタが増える。あと冠詞EがRにかわる。
記法
アセンブリ記法にはおもに2つある。
AT&T記法
gdbとかだとdefaultでこれ。レジスタ名に%がついてたり、即値に$がついてたりする。
mov %ebx,%eax
-> ebx を eax に 代入
Intel記法
今日良く見るのはこれ。AT&T記法とオペランドの順序が逆になるので注意。
mov EAX,EBX
-> ebx を eax に 代入
ニーモニック(mnemonic)
IA32(x86)汎用命令一覧
この表の読み方
- オペコード - 対応する機械語
- imm - immediate valueかな。即値と訳される。変数でなく、直接埋め込まれる値。リテラルというとわかりやすいか。
- r - register。レジスタ名を指定する。EIP,EFLAGSあたりは特殊なレジスタなのでここに書くことはできない(と思う)。
- r/m - レジスタorメモリのアドレス
簡単な紹介
- ADD A,B - AにBを加算(し、Aに結果を格納)
- PUSH A - Aをスタックにプッシュ
- POP A - スタックからポップし、Aに代入
- CMP A,B - A-Bを計算し、結果は破棄する。結果によってFLAGSが変化する。
- JMP A - Aにジャンプ
- JZ(resp. JA) A - もしZF=1(resp. CF=0 and ZF=0)ならば、Aにジャンプ
- CALL - 関数呼び出し
- RET - 関数呼び出し位置に戻る
関数呼び出し
基本的な流れは、
- パラメータを格納
- CALL
- BPをsave
- BPを自分用に新しくする
- ローカル変数用にスタック領域確保 (SPを減ずる)
- 保存すべきレジスタを保存
- 処理~
- 保存すべきレジスタを戻す
- スタック領域破棄(SPを加える)
- BPも戻す
- RET
- パラメータを破棄
となるが、いろいろと自由度がある。
x86 calling conventions - Wikipedia
- The order in which atomic (scalar) parameters, or individual parts of a complex parameter, are allocated
- How parameters are passed (pushed on the stack, placed in registers, or a mix of both)
- Which registers the callee must preserve for the caller
- How the task of preparing the stack for, and restoring after, a function call is divided between the caller and the callee
x64になってくると、パラメータをレジスタ渡しするようになって、そのとき使うレジスタが変わってくるので注意。x64 Assembly Programming