METASM
METASMはRubyで記述されている、アセンブラ、逆アセンブラ、コンパイラ、リンカ、デバッガといった機能を持つライブラリ/アプリケーションである。
- 対応アーキテクチャ
- x86_64,ia32,mips,ppc (unstable: arc,arm,bpf,cy16,dalvik,python,sh4,z80)
- 対応フォーマット
- a.out,elf,pe,raw,Mach-O,nds,xcoffなど
逆アセンブラの主な特徴は以下の通り。
- 関数を自動で識別し、呼び出し元などを列挙してくれる
- Windowsの関数呼び出しもある程度関数名を表示してくれる
- 逆コンパイルすることが出来る
- 関数の呼び出しグラフや関数内でのジャンプグラフなどを表示することが出来る(GUI版)
- 文字列参照をコメントで表示することが出来る
- ローカル変数を列挙することが出来る
目次
インストール
GITHUBからリポジトリをクローンする。
$ git clone https://github.com/jjyg/metasm/ ~/local/metasm
環境変数RUBYLIBにmetasmのディレクトリを追加する。.bashrcや.zshenvなどに以下を記述。
[[ -s "$HOME/local/metasm" ]] && export RUBYLIB="$HOME/local/metasm"
gtk2-gemをインストールする(GUI版の逆アセンブラーを使う場合のみ)
$ gem install gtk2
ツール
samplesディレクトリに利用例としてツールが入っている。(大体はRubyから扱うためのSampleである)
- disassemble.rb
- 逆アセンブラ
- disassemble-gui.rb
- GUI版逆アセンブラ。ファイルの編集が出来たり、関数の分岐などをグラフにして表示する機能があったりする。
- lindebug.rb
- Win32/Linux用のラインデバッガー
逆アセンブラ(CUI)
基本的な利用方法
$ ruby disassmble.rb --cpu <CPU名> --exe <ファイルフォーマット> [その他オプション] 実行ファイル
--cpuや--exeを省略しても自動的に適切なものを選んでくれる
逆アセンブル
デフォルトでちゃんとbacktraceしてくれる。
関数の呼び出し元なども表示してくれるのが便利。
$ ruby disassemble.rb --cpu x86_64 --exe ELF a.out // ELF segment at 400000h, flags = R, X db 7fh, "ELF", 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; @400000h db 2, 0, 3eh, 0, 1, 0, 0, 0, 40h, 4, 40h, 0, 0, 0, 0, 0 ; @400010h db 40h, 0, 0, 0, 0, 0, 0, 0, 38h, 0bh, 0, 0, 0, 0, 0, 0 ; @400020h (中略) // Xrefs: __libc_start_main main: // function binding: r10,r11,r8,r9,rcx,rdi,rdx -> unknown, rax -> 0, rsp -> rsp+8 // function ends at 400539h push rbp ; @40050ch 55 mov rbp, rsp ; @40050dh 4889e5 (省略)
backtraceのせいで逆コンパイルが終わらない場合は、--fastオプションを付与すると良い。
使用例
Shellcodeの逆アセンブル
$ ruby ~/local/metasm/samples/disassemble.rb --cpu X64 --exe Shellcode shellcode.raw entrypoint_0: // function binding: rax -> 8, rsp -> rsp+8 // function ends at 7 lea rax, [rip-7+8] ; @0 488d0501000000 ret ; @7 c3 endsub entrypoint_0 db "aaa", 0 ; @8
逆コンパイル
2015年4月現在、実用性はほとんどない。いろいろと間違ってるし。
1 $ ruby disassemble.rb --decompile --cpu x86_64 --exe ELF a.out
2 (中略)
3
4 int main __attribute__((stackoff:-8))(int rbp __attribute__((register(rbp))), int rdi __attribute__((register(rdi))))
5 {
6 register int eax __attribute__((register(eax)));
7 register int rbp_a0 __attribute__((register(rbp)));
8 register int rsp __attribute__((register(rsp)));
9 register int rsp_a0 __attribute__((register(rsp)));
10 rsp_a0 = (rsp - 8);
11 *(int*)(rsp_a0 - 8) = rbp;
12 rbp_a0 = rsp_a0;
13 *(int*)(rbp_a0 - 4) = rdi;
14 *(__int32*)(rbp_a0 - 4) != 1;
15 puts();
16 return eax;
17 }
逆アセンブラ(GUI)
基本的な利用方法
次のようにして起動する。
ruby metasm/samples/disassmble-gui.rb --cpu <CPU名> --exe <ファイルフォーマット> [その他オプション] 実行ファイル
キーボードショートカット
キー |
効果 |
c |
逆アセンブル |
C |
逆アセンブル(バックトラックなし、関数呼び出し無視) |
Ctrl+C |
逆アセンブル(バックトラックなし) |
g |
特定アドレスへ移動 |
Return |
callやjmpを辿る |
Esc |
元の場所に戻る |
Ctrl+Enter |
元の場所に戻るのをやりなおし |
f |
関数一覧を表示 |
x |
呼び出し元を列挙 |
K |
関数内のローカル変数に名前を付ける |
b |
backtrace |
n |
ラベルの名前を変更する |
Tab |
逆コンパイル |
/ |
検索 |
Ctrl+f |
正規表現検索し、列挙する |
ライブラリ
シェルコード
RubyのExploit上で直接Shellcodeを書くことが可能になる。
デバッガ
プロセスを実行する
Metasm::OS.currentで現在のOSを取得することが出来る。(Metasm::LinOSかMetasm::WinOSのどちらか)
OS.create_processにより新規プロセスをコマンドを指定して実行出来る。
プロセスにアタッチする
標準入出力を確保してプロセスを実行する
ブレークポイント
ソフトウェアブレークポイント
Debugger.bpx(アドレス, 一度のみか, &callback)
ハードウェアブレークポイント
Debugger.hwbp(アドレス, タイプ(:r, :w, :x)のどれか, メモリサイズ, 一度のみか, &callback)
メモリアクセスブレークポイント
現在実装されていない
Debugger.mbp(アドレス, タイプ(:r, :w)のどれか, メモリサイズ, 一度のみか, &callback)
アンチ・アンチデバッギング
Windows, is_debugger_present対策
1 dbg[process.peb_base + 0x02, 1] = "\0" # is_debbuger_present() => falseにする