ログイン
編集不可のページディスカッション情報添付ファイル
"CTF/Toolkit/METASM"の差分

MMA
2と18のリビジョン間の差分 (その間の編集: 16回)
2014-01-07 12:49:18時点のリビジョン2
サイズ: 4722
編集者: nomeaning
コメント:
2015-05-04 16:43:42時点のリビジョン18
サイズ: 6825
編集者: nomeaning
コメント:
削除された箇所はこのように表示されます。 追加された箇所はこのように表示されます。
行 2: 行 2:
METASMはPure Rubyで記述されている、アセンブラ、逆アセンブラ、コンパイラ、リンカ、デバッガーである。 METASMはRubyで記述されている、アセンブラ、逆アセンブラ、コンパイラ、リンカ、デバッガといった機能を持つライブラリ/アプリケションである。
行 10: 行 10:
ドキュメントはソースコード
行 14: 行 12:
リポジトリをクローンする。 GITHUBからリポジトリをクローンする。
行 22: 行 20:
関連gemをインストールする(GUI逆アセンブラーを使う場合のみ) gtk2-gemをインストールする(GUI版の逆アセンブラーを使う場合のみ)
行 27: 行 25:
== Tools == == ツール ==
行 30: 行 28:
 *disassemble.rb
  *CLI版逆アセンブラ。
行 31: 行 31:
  *GUI版逆アセンブラ。ファイルの編集が出来たり、関数の分岐などをグラフにして表示する機能があったりする。
 *disassemble.rb
  *逆アセンブラ
  *GUI版逆アセンブラ。グラフビューを持つ。
行 35: 行 33:
  *Win32/Linux用のラインデバッガー
有用性が微妙なもの
 *bindiff.rb
  *ふたつの逆アセンブルを比較する
 *dump_upx.rb
  *UPXをUnpackする
 *struct_offset.rb
  *構造体の要素の位置を調べる
== 逆アセンブラ ==
=== 基本的な利用方法 ===
  *Win32/Linux用のラインデバッガ

=== 逆アセンブラ(CUI) ===
==== 基本的な利用方法 ====
行 50: 行 42:
=== 逆アセンブル(CUI) ===
デフォルトでちゃんとbacktraceしてくれる。
==== 逆アセンブル ====
backtraceのせいで逆コンパイルが終わらない場合は、`--fast`オプションを付与すると良い。
行 53: 行 45:
関数の呼び出し元なども表示してくれるのが便利。 ===== 使用例 =====
ELFの逆アセンブル
行 55: 行 48:
$ ruby disassemble.rb --cpu x86_64 --exe ELF a.out                               $ ruby disassemble.rb --cpu x86_64 --exe ELF a.out
行 65: 行 58:
    push rbp ; @40050ch 55
    mov rbp, rsp ; @40050dh 4889e5
    sub rsp, 10h ; @400510h 4883ec10
    mov [rbp-4], edi ; @400514h 897dfc
    cmp dword ptr [rbp-4], 1 ; @400517h 837dfc01
    jnz loc_400529h ; @40051bh 750c x:loc_400529h
    push rbp ; @40050ch 55
    mov rbp, rsp ; @40050dh 4889e5
(省略)
}}}
行 72: 行 63:
    mov edi, 4005ech ; @40051dh bfec054000
    call thunk_puts ; @400522h e8b9feffff x:thunk_puts
    jmp loc_400533h ; @400527h eb0a x:loc_400533h
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
}}}
行 77: 行 75:
// Xrefs: 40051bh
loc_400529h:
    mov edi, 4005f2h ; @400529h bff2054000
    call thunk_puts ; @40052eh e8adfeffff x:thunk_puts


// Xrefs: 400527h
loc_400533h:
    mov eax, 0 ; @400533h b800000000
    leave ; @400538h c9
    ret ; @400539h c3 endsub main
db 90h, 90h, 90h, 90h, 90h, 90h ; @40053ah

// Xrefs: __libc_start_main
(以下省略)
}}}

=== 逆コンパイル ===
Boomerangと違って64bit ELFファイルの逆コンパイルもしてくれるが実用性はほとんどない。いろいろと間違ってるし。
==== 逆コンパイル ====
2015年4月現在、実用性はほとんどない。いろいろと間違ってるし。
行 116: 行 97:
== シェルコード == === 逆アセンブラ(GUI) ===
==== 起動方法 ====
次のようにして起動する。
{{{
ruby metasm/samples/disassmble-gui.rb --cpu <CPU名> --exe <ファイルフォーマット> [その他オプション] 実行ファイル
}}}

==== キーボードショートカット ====
||<ROWCLASS="header"> キー || 効果 ||
|| c || 逆アセンブル ||
|| C || 逆アセンブル(バックトラックなし、関数呼び出し無視) ||
|| Ctrl+C || 逆アセンブル(バックトラックなし) ||
|| g || 特定アドレスへ移動 ||
|| Return || callやjmpを辿る ||
|| Esc || 元の場所に戻る ||
|| Ctrl+Enter || 元の場所に戻るのをやりなおし ||
|| f || 関数一覧を表示 ||
|| x || 呼び出し元を列挙 ||
|| K || 関数内のローカル変数に名前を付ける ||
|| b || backtrace ||
|| n || ラベルの名前を変更する ||
|| Tab || 逆コンパイル ||
|| / || 検索 ||
|| Ctrl+f || 正規表現検索し、列挙する ||

== ライブラリ ==
=== シェルコード ===
行 127: 行 134:

=== デバッガ ===
==== プロセスを実行する ====
Metasm::OS.currentで現在のOSを取得することが出来る。(Metasm::LinOSかMetasm::WinOSのどちらか)

OS.create_processにより新規プロセスをコマンドを指定して実行出来る。
{{{#!highlight ruby
require 'metasm'

process = Metasm::OS.current.create_process('./a.out')
# 引数を渡す場合は process = Metasm::OS.current.create_process('./a.out ARGV1 ARGV2')
debugger = process.debugger
debugger.run_forever
}}}

==== プロセスにアタッチする ====
{{{#!highlight ruby
# 特定の名前またはpidを持つ最初のプロセスを返す
pid = Metasm::OS.current.find_process('./a.out').pid

process = Metasm::OS.current.open_process(pid)
debugger = process.debugger
}}}

==== 標準入出力を確保してプロセスを実行する ====
{{{#!highlight ruby
io = IO.popen(['./a.out', 'aaa'], 'r+')
debugger = Metasm::OS.current.open_process(io.pid).debugger
}}}

==== ブレークポイント ====
===== ソフトウェアブレークポイント =====
`Debugger.bpx(アドレス, 一度のみか, &callback)`
{{{#!highlight ruby
debugger.bpx(0x40051d, true) do
  puts "eax=#{debuger[:eax]}"
end
}}}

===== ハードウェアブレークポイント =====
`Debugger.hwbp(アドレス, タイプ(:r, :w, :x)のどれか, メモリサイズ, 一度のみか, &callback)`
{{{#!highlight ruby
debugger.hwbp(0x40051d, :x, 1, true) do
  puts "eax=#{debuger[:eax]}"
end
}}}

===== メモリアクセスブレークポイント =====
{{{#!wiki note
現在実装されていない
}}}
`Debugger.mbp(アドレス, タイプ(:r, :w)のどれか, メモリサイズ, 一度のみか, &callback)`
{{{#!highlight ruby
debugger.mbp(0x40051d, :r, 1, true) do
  puts "Access"
end
}}}
==== アンチ・アンチデバッギング ====
===== Windows, is_debugger_present対策 =====
{{{#!highlight ruby
dbg[process.peb_base + 0x02, 1] = "\0" # is_debbuger_present() => falseにする
}}}

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など

http://metasm.cr0.org/

インストール

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
    • CLI版逆アセンブラ。
  • disassemble-gui.rb
    • GUI版逆アセンブラ。グラフビューを持つ。
  • lindebug.rb
    • Win32/Linux用のラインデバッガ

逆アセンブラ(CUI)

基本的な利用方法

$ ruby disassmble.rb --cpu <CPU名> --exe <ファイルフォーマット> [その他オプション] 実行ファイル

--cpu--exeを省略しても自動的に適切なものを選んでくれる

逆アセンブル

backtraceのせいで逆コンパイルが終わらない場合は、--fastオプションを付与すると良い。

使用例

ELFの逆アセンブル

$ 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
(省略)

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を書くことが可能になる。

   1 require 'metasm'
   2 
   3 print Metasm::Shellcode.assemble(Metasm::Ia32.new, <<SOURCE).encode_string
   4 mov eax, 1
   5 mov ebx, 42
   6 int 80h         // exit
   7 SOURCE
   8 

デバッガ

プロセスを実行する

Metasm::OS.currentで現在のOSを取得することが出来る。(Metasm::LinOSかMetasm::WinOSのどちらか)

OS.create_processにより新規プロセスをコマンドを指定して実行出来る。

   1 require 'metasm'
   2 
   3 process = Metasm::OS.current.create_process('./a.out')
   4 # 引数を渡す場合は process = Metasm::OS.current.create_process('./a.out ARGV1 ARGV2')
   5 debugger = process.debugger
   6 debugger.run_forever

プロセスにアタッチする

   1 # 特定の名前またはpidを持つ最初のプロセスを返す
   2 pid = Metasm::OS.current.find_process('./a.out').pid
   3 
   4 process = Metasm::OS.current.open_process(pid)
   5 debugger = process.debugger

標準入出力を確保してプロセスを実行する

   1 io = IO.popen(['./a.out', 'aaa'], 'r+')
   2 debugger = Metasm::OS.current.open_process(io.pid).debugger

ブレークポイント

ソフトウェアブレークポイント

Debugger.bpx(アドレス, 一度のみか, &callback)

   1 debugger.bpx(0x40051d, true) do 
   2   puts "eax=#{debuger[:eax]}"
   3 end

ハードウェアブレークポイント

Debugger.hwbp(アドレス, タイプ(:r, :w, :x)のどれか, メモリサイズ, 一度のみか, &callback)

   1 debugger.hwbp(0x40051d, :x, 1, true) do 
   2   puts "eax=#{debuger[:eax]}"
   3 end

メモリアクセスブレークポイント

現在実装されていない

Debugger.mbp(アドレス, タイプ(:r, :w)のどれか, メモリサイズ, 一度のみか, &callback)

   1 debugger.mbp(0x40051d, :r, 1, true) do 
   2   puts "Access"
   3 end

アンチ・アンチデバッギング

Windows, is_debugger_present対策

   1 dbg[process.peb_base + 0x02, 1] = "\0" # is_debbuger_present() => falseにする

CTF/Toolkit/METASM (最終更新日時 2016-02-12 13:56:08 更新者 nomeaning)