Github: https://github.com/cea-sec/miasm
Pythonでのリバースエンジニアリングフレームワーク
目次
ミアムとは何ですか?
Miasmは、フリーでオープンソースの(GPLv2)リバースエンジニアリングフレームワークです。 Miasmはバイナリプログラムの解析/修正/生成を目指しています。 ここには網羅的ではない機能のリストがあります:
- Elfesteemを使用したPE / ELF 32/64 LE / BEのオープン/変更/生成
- X86 / ARM / MIPS / SH4 / MSP430のアセンブル/ディスアセンブル
- 中間言語を用いたアセンブリ意味の表現
- JITを使用したエミュレーション(動的コード解析、アンパック、…)
- 自動解読不能化のための式の簡素化
- …
例とデモの詳細については、公式ブログを参照してください。
基本的な例
アセンブル/ディスアセンブル
Miasm x86アーキテクチャをインポートする:
>>> from miasm2.arch.x86.arch import mn_x86
ラインを組み立てる:
>>> l = mn_x86.fromstring('XOR ECX, ECX', 32)
>>> print l
XOR ECX, ECX
>>> mn_x86.asm(l)
['1\xc9', '3\xc9', 'g1\xc9', 'g3\xc9']
オペランドを変更する:
>>> l.args[0] = mn_x86.regs.EAX
>>> print l
XOR EAX, ECX
>>> a = mn_x86.asm(l)
>>> print a
['1\xc8', '3\xc1', 'g1\xc8', 'g3\xc1']
結果を逆アセンブルします。
>>> print mn_x86.dis(a[0], 32)
XOR EAX, ECX
Machine
抽象化の使用:
>>> from miasm2.analysis.machine import Machine
>>> mn = Machine('x86_32').mn
>>> print mn.dis('\x33\x30', 32)
XOR ESI, DWORD PTR [EAX]
Mipsの場合:
>>> mn = Machine('mips32b').mn
>>> print mn.dis('97A30020'.decode('hex'), "b")
LHU V1, 0x20(SP)
中間表現
命令を作成する:
>>> machine = Machine('arml')
>>> l = machine.mn.dis('002088e0'.decode('hex'), 'l')
>>> print l
ADD R2, R8, R0
中間表現(IR)オブジェクトを作成する:
>>> ira = machine.ira()
プールに命令を追加する:
>>> ira.add_instr(l)
現在のプールを印刷する:
>>> for lbl, b in ira.blocs.items():
... print b
...
loc_0000000000000000:0x00000000
R2 = (R8+R0)
IRDst = loc_0000000000000004:0x00000004
例えば、副作用を起こしてIRを扱う:
>>> from miasm2.expression.expression import get_rw
>>> for lbl, b in ira.blocs.items():
... for irs in b.irs:
... o_r, o_w = get_rw(irs)
... print 'read: ', [str(x) for x in o_r]
... print 'written:', [str(x) for x in o_w]
... print
...
read: ['R8', 'R0']
written: ['R2']
read: ['loc_0000000000000004:0x00000004']
written: ['IRDst']
エミュレーション
シェルコードを与える:
00000000 8d4904 lea ecx, [ecx+0x4]
00000003 8d5b01 lea ebx, [ebx+0x1]
00000006 80f901 cmp cl, 0x1
00000009 7405 jz 0x10
0000000b 8d5bff lea ebx, [ebx-1]
0000000e eb03 jmp 0x13
00000010 8d5b01 lea ebx, [ebx+0x1]
00000013 89d8 mov eax, ebx
00000015 c3 ret
>>> s = '\x8dI\x04\x8d[\x01\x80\xf9\x01t\x05\x8d[\xff\xeb\x03\x8d[\x01\x89\xd8\xc3'
Container
抽象化によってシェルコードをインポートする:
>>> from miasm2.analysis.binary import Container
>>> c = Container.from_string(s)
>>> c
<miasm2.analysis.binary.ContainerUnknown object at 0x7f34cefe6090>
アドレス0
のシェルコードを逆アセンブルする:
>>> from miasm2.analysis.machine import Machine
>>> machine = Machine('x86_32')
>>> mdis = machine.dis_engine(c.bin_stream)
>>> blocs = mdis.dis_multiblock(0)
>>> for b in blocs:
... print b
...
loc_0000000000000000:0x00000000
LEA ECX, DWORD PTR [ECX+0x4]
LEA EBX, DWORD PTR [EBX+0x1]
CMP CL, 0x1
JZ loc_0000000000000010:0x00000010
-> c_next:loc_000000000000000B:0x0000000b c_to:loc_0000000000000010:0x00000010
loc_0000000000000010:0x00000010
LEA EBX, DWORD PTR [EBX+0x1]
-> c_next:loc_0000000000000013:0x00000013
loc_000000000000000B:0x0000000b
LEA EBX, DWORD PTR [EBX+0xFFFFFFFF]
JMP loc_0000000000000013:0x00000013
-> c_to:loc_0000000000000013:0x00000013
loc_0000000000000013:0x00000013
MOV EAX, EBX
RET
>>>
Jitエンジンをスタックで初期化する:
>>> jitter = machine.jitter(jit_type='python')
>>> jitter.init_stack()
任意のメモリ位置にシェルコードを追加する:
>>> run_addr = 0x40000000
>>> myjit.vm.add_memory_page(run_addr, PAGE_READ | PAGE_WRITE, s)
シェルコードの戻り値をキャッチするためにセンチネルを作成する:
def code_sentinelle(jitter):
jitter.run = False
jitter.pc = 0
return True
>>> jitter.add_breakpoint(0x1337beef, code_sentinelle)
>>> jitter.push_uint32_t(0x1337beef)
アクティブなログ:
>>> jitter.jit.log_regs = True
>>> jitter.jit.log_mn = True
任意のアドレスで実行:
>>> jitter.init_run(run_addr)
>>> jitter.continue_run()
RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000000 RDX 0000000000000000
RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000
zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000
RIP 0000000040000000
40000000 LEA ECX, DWORD PTR [ECX+0x4]
RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000
RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000
zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000
....
4000000e JMP loc_0000000040000013:0x40000013
RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000
RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000
zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000
RIP 0000000040000013
40000013 MOV EAX, EBX
RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000
RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000
zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000
RIP 0000000040000013
40000015 RET
>>>
ジッタと対話する:
>>> jitter.vm
ad 1230000 size 10000 RW_ hpad 0x2854b40
ad 40000000 size 16 RW_ hpad 0x25e0ed0
>>> hex(jitter.cpu.EAX)
'0x0L'
>>> jitter.cpu.ESI = 12
記号的実行
IRプールの初期化:
>>> ira = machine.ira()
>>> for b in blocs:
... ira.add_bloc(b)
...
デフォルトの記号値でエンジンを初期化する:
>>> from miasm2.ir.symbexec import symbexec
>>> sb = symbexec(ira, machine.mn.regs.regs_init)
実行を開始する:
>>> symbolic_pc = sb.emul_ir_blocs(ira, 0)
>>> print symbolic_pc
((ECX_init+0x4)[0:8]+0xFF)?(0xB,0x10)
ステップ・ログと同じです(変更のみが表示されます)。
>>> sb = symbexec(ira, machine.mn.regs.regs_init)
>>> symbolic_pc = sb.emul_ir_blocs(ira, 0, step=True)
________________________________________________________________________________
ECX (ECX_init+0x4)
________________________________________________________________________________
ECX (ECX_init+0x4)
EBX (EBX_init+0x1)
________________________________________________________________________________
zf ((ECX_init+0x4)[0:8]+0xFF)?(0x0,0x1)
nf ((ECX_init+0x4)[0:8]+0xFF)[7:8]
pf (parity ((ECX_init+0x4)[0:8]+0xFF))
of ((((ECX_init+0x4)[0:8]+0xFF)^(ECX_init+0x4)[0:8])&((ECX_init+0x4)[0:8]^0x1))[7:8]
cf (((((ECX_init+0x4)[0:8]+0xFF)^(ECX_init+0x4)[0:8])&((ECX_init+0x4)[0:8]^0x1))^((ECX_init+0x4)[0:8]+0xFF)^(ECX_init+0x4)[0:8]^0x1)[7:8]
af (((ECX_init+0x4)[0:8]+0xFF)&0x10)?(0x1,0x0)
ECX (ECX_init+0x4)
EBX (EBX_init+0x1)
________________________________________________________________________________
IRDst ((ECX_init+0x4)[0:8]+0xFF)?(0xB,0x10)
zf ((ECX_init+0x4)[0:8]+0xFF)?(0x0,0x1)
nf ((ECX_init+0x4)[0:8]+0xFF)[7:8]
pf (parity ((ECX_init+0x4)[0:8]+0xFF))
of ((((ECX_init+0x4)[0:8]+0xFF)^(ECX_init+0x4)[0:8])&((ECX_init+0x4)[0:8]^0x1))[7:8]
cf (((((ECX_init+0x4)[0:8]+0xFF)^(ECX_init+0x4)[0:8])&((ECX_init+0x4)[0:8]^0x1))^((ECX_init+0x4)[0:8]+0xFF)^(ECX_init+0x4)[0:8]^0x1)[7:8]
af (((ECX_init+0x4)[0:8]+0xFF)&0x10)?(0x1,0x0)
EIP ((ECX_init+0x4)[0:8]+0xFF)?(0xB,0x10)
ECX (ECX_init+0x4)
EBX (EBX_init+0x1)
具体的なECXで実行を再試行してください。 ここで、シンボリック/コンコードの実行はシェルコードの終わりに達します:
>>> from miasm2.expression.expression import ExprInt32
>>> sb.symbols[machine.mn.regs.ECX] = ExprInt32(-3)
>>> symbolic_pc = sb.emul_ir_blocs(ira, 0, step=True)
________________________________________________________________________________
ECX 0x1
________________________________________________________________________________
ECX 0x1
EBX (EBX_init+0x1)
________________________________________________________________________________
zf 0x1
nf 0x0
pf 0x1
of 0x0
cf 0x0
af 0x0
ECX 0x1
EBX (EBX_init+0x1)
________________________________________________________________________________
IRDst 0x10
zf 0x1
nf 0x0
pf 0x1
of 0x0
cf 0x0
af 0x0
EIP 0x10
ECX 0x1
EBX (EBX_init+0x1)
________________________________________________________________________________
IRDst 0x10
zf 0x1
nf 0x0
pf 0x1
of 0x0
cf 0x0
af 0x0
EIP 0x10
ECX 0x1
EBX (EBX_init+0x2)
________________________________________________________________________________
IRDst 0x13
zf 0x1
nf 0x0
pf 0x1
of 0x0
cf 0x0
af 0x0
EIP 0x10
ECX 0x1
EBX (EBX_init+0x2)
________________________________________________________________________________
IRDst 0x13
zf 0x1
nf 0x0
pf 0x1
of 0x0
cf 0x0
af 0x0
EIP 0x10
EAX (EBX_init+0x2)
ECX 0x1
EBX (EBX_init+0x2)
________________________________________________________________________________
IRDst @32[ESP_init]
zf 0x1
nf 0x0
pf 0x1
of 0x0
cf 0x0
af 0x0
EIP @32[ESP_init]
EAX (EBX_init+0x2)
ECX 0x1
EBX (EBX_init+0x2)
ESP (ESP_init+0x4)
>>> print symbolic_pc
@32[ESP_init]
>>> sb.dump_id()
IRDst @32[ESP_init]
zf 0x1
nf 0x0
pf 0x1
of 0x0
cf 0x0
af 0x0
EIP @32[ESP_init]
EAX (EBX_init+0x2)
ECX 0x1
EBX (EBX_init+0x2)
ESP (ESP_init+0x4)
どのように機能するのですか?
Miasmは、独自の逆アセンブラ、中間言語、命令セマンティックを組み込みます。 これはPythonで書かれています。
コードをエミュレートするために、LibTCC、LLVM、GCC、ClangまたはPythonを使用して、中間表現をJITします。 シェルコードとバイナリの全部または一部をエミュレートできます。 実行と対話するために、例えばライブラリ関数のエフェクトをエミュレートするために、Pythonコールバックを実行することができます。
ドキュメンテーション
TODO
ここでは自動生成されたドキュメントが利用できます 。
重度を得る
- リポジトリをクローン: GitHubのMiasm
- Docker HubでDockerイメージの1つを取得する
ソフトウェア要件
Miasmは以下を使用します。
- python-pyparsing
- python-dev
- エルフェシュテームからのエルフェシュテーム
- オプションでpython-pycparser(バージョン> = 2.17)
コードJITを有効にするには、次のいずれかのモジュールが必須です。
- GCC
- クラング
- LLVM with Numba llvmlite、以下を参照してください
- LibTCC tinycc(オンリーバージョン0.9.26)
‘optional’ Miasmは以下を使用することもできます:
- Z3、 Theorem Prover
構成
- インストールelfesteem
git clone https://github.com/serpilliere/elfesteem.git elfesteem
cd elfesteem
python setup.py build
sudo python setup.py install
ジッタを使用するには、GCC、TCCまたはLLVMを推奨します
- GCC(任意のバージョン)
- Clang(任意のバージョン)
- LibTCCは
--disable-static
オプションで設定する必要があります- 競合を避けるために
libtcc-dev
をシステムから削除してください - クローンTinyCC :
git clone http://repo.or.cz/tinycc.git
- バージョン0.9.26にブランチを設定してください:
cd tinycc/
とgit checkout release_0_9_26
-
./configure --disable-static
-
make
-
sudo make install
- ドキュメントの生成にエラーがある可能性があります
- 競合を避けるために
- LLVM
- Debian(テスト/不安定):テストされていません
- Debian stable / Ubuntu / Kali / whatever:
pip install llvmlite
またはllvmliteからインストールする - Windows:テストされていない
- Miasmのビルドとインストール:
$ cd miasm_directory
$ python setup.py build
$ sudo python setup.py install
ジッタモジュールのコンパイル中に問題が発生すると、Miasmはエラーをスキップして対応するモジュールを無効にします(コンパイル出力を参照)。
Windows&IDA
MiasmのIDAプラグインのほとんどは、Miasmの機能性のサブセットを使用します。 それらを動作させる簡単な方法は次のものを追加することです:
-
elfesteem
ディレクトリとpyparsing.py
をC:\...\IDA\python\
またはpip install pyparsing elfesteem
-
miasm2/miasm2
ディレクトリからC:\...\IDA\python\
JITter関連の機能を除くすべての機能を利用できます。 より完全なインストールについては、上記の段落を参照してください。
テスト
Miasmには一連の回帰テストが付属しています。 それらをすべて実行するには:
cd miasm_directory/test
python test_all.py
いくつかのオプションを指定することができます:
- モノスレッド:
-m
- コードカバレッジ計測:
-c
- 高速テストのみ:
-t long
(長いテストを除く)
彼らはすでにMiasmを使用しています
ツール
- シビル :機能の占いも
- R2M2 :radias2プラグインとしてmiasm2を使用する
- CGrex :CGCバイナリのターゲットパッチ
- ethrie Ethereum EVMのリバースツール(対応するMiasm2アーキテクチャを使用)
ブログ投稿/論文/会議
- Deobfuscation:OLLVMで保護されたプログラムを回復する
- 象徴的な実行を伴う野生型ナノメーター保護MIPSバイナリの試行:そのような亀裂はない
- Diana avec Miasm : DGAの素早い計算(フランス語記事)
- 多様化と情報を克服するためのクライアント側の耐故障性の有効化隠蔽 :無向呼び出し可能な引数を検出する
- Miasm:フレームワークdeリバースエンジニアリング (フランス語)
- チュートリアルミアム (フランス語ビデオ)
- ディフェンション:プチプーケットスタイル :DepGraph(フランス語)
書籍
- 実用的なリバースエンジニアリング:X86、X64、アーム、Windowsカーネル、リバースツール、難読化 :ミアム入門(第5章「難読化」)
- BlackHat Python – 付録 :日本のセキュリティブックのサンプル
その他
- 男、miasmにrr0dとのリンクがありますか?
- はい! 愚かなコードと醜いドキュメント。