GIAC Reverse Engineering Malware (GREM) 2日目 Reversing Malicious Codeのメモ。
cdel、stdcall、fastcall、thiscall
関数の呼び出しの形式として、cdel、stdcall、fastcall、thiscallがある。
cdel (C Declaration convention)
- 引数は右から左の順番でスタックに積まれる
- 戻り値はEAXに格納される
- 関数の呼び出し元がスタックの後始末をする (call命令のあとにadd命令等でESPを操作してスタックを掃除する)
stdcall (Standard Calling convention)
- 引数は右から左の順番でスタックに積まれる
- スタックの後始末は呼び出された関数が行う (関数内で最後にスタックを掃除するので、call命令のあとにESPを操作する命令は無い)
- 主にWindows APIを呼び出したときに使用される形式
fastcall
- 引数は、まずECXとEDXに格納される
- ECXとEDXに格納できなかった引数はスタックに積まれる
- 戻り値はEAXに格納される
- スタックの後始末は呼び出された関数が行う
thiscall
- 主にC++プログラムで使われる形式
- この形式にはthisポインタが含まれる
- Microsoftコンパイラの場合はthisポインタはECXに格納され、スタックの後始末は呼び出された関数が行う
- GNUコンパイラの場合はthisポインタは最後にスタックに積まれ、スタックの後始末は関数の呼び出し元が行う
JC (Jump if Carry)はJB (Jump if Below)と同義
64ビットのプログラムについて
- EIPはRIPとなる
- 引数と変数のアクセスにはRSPが使われる (RBPではない)
- 関数の呼び出し形式はfastcallに類似している
- 最初の4つの引数はレジスタに格納される (1つ目: RCX、2つ目: RDX、3つ目: R8、4つ目: R9 )
- 5つ目以降の引数はスタックに積まれる
- RIPからの相対アドレスでメモリ領域を参照する
- 従来の32ビット・プログラムではプログラムやDLLがBase Addressにロードされなかった場合、アドレスのリロケーションを行わなければならなかった
- RIP (current instruction pointer) からの相対アドレスでメモリ領域を参照することにより、上記のアドレスのリロケーション作業が不要になった
- これによりPIC (Position Independent Code) を書くことが容易になった
- RIPからの相対アドレスでデータにアクセスできるので、攻撃者にとってもシェルコードを書くのが容易になった (32ビット・プログラムで動作するシェルコードは、諸々のデータにアクセスするために、まずEIPを取得する必要がある。詳しくはこちらの記事の「GetEIPについて」の項を参照)
Ghidra 雑感
本トレーニング・コースで使用するディスアセンブラはGhidraだった。自分はもっぱらIDAを使っていたのでGhidraは初体験だった。Ghidraで新規に検体をロードするには以下のようにする。
- File > New Project
- Non-Shared ProjectかShared Projectのどちらかを選択してNextをクリック
- プロジェクト名を入力してFinishをクリック
- 作成されたプロジェクトのウィンドウに検体をドラッグ&ドロップして (またはFile -> Import File) OKをクリック
- プロジェクト・ウインドウにインポートされた検体をダブル・クリック
- 解析を開始するか聞かれるのでYesをクリック
- 解析のオプション画面が表示されるので、必要なオプションを適宜選択する。本コースでは「WindowsPE x86 Propagate External Parameters」のオプションを必ず有効化することを推奨していた。
- オプションの選択が完了したらAnalyzeボタンをクリック
- Ghidraが検体のディスアセンブルを開始する。完了するのに大体数分かかる。
初めてGhidraに触れたが、IDAに比べると検体をロードするのに時間がかかったり、IDAなら自動でパースしてくれるようなものをオプションの有効化・無効化で手動でパースしなければならない、という印象を受けた。もしIDAを使う選択肢があるなら、迷わずIDAを使うと思う。ちなみにコース用のVMにはIDAもインストールされていた。