
Pure Rust製x86ハードウェアエミュレータおよびWindowsプロセスシミュレータ。マルウェア解析、シェルコードエミュレーション、ペイロードアンパックに対応。32/64ビットPE実行ファイル、Metasploit、Cobalt Strike、複雑なマルウェアファミリをサポートします。
純粋なRustで実装されたハードウェアエミュレータ + OSプロセスシミュレータです。
このアプローチはマルウェア解析やその他の処理(PE、シェルコードなど)に非常に便利です。
OSは主にWindowsで、Windowsプロセスをエミュレートします。Linuxの基本的なサポートもあります。
ハードウェアはx86 32/64ビットで、高速かつ信頼性があります。

プロジェクト名は scemu から mwemu に変更されました。
r2con2025 mwemu から radare2 を使用して、エミュレーション中に静的解析と可視化を行う方法。
📦 Rustの安全性。マルウェアのエミュレーションに最適。
⚡ 非常に高速なエミュレーション
iced-x86 Rust逆アセンブラという素晴らしいライブラリを採用。
コマンドラインツール、Rustライブラリ、Pythonライブラリを提供。
反復検出器。
メモリとレジスタの追跡。
カラー表示。
特定の瞬間に停止して状態を調査・変更可能。
339のCPU命令を実装。
15のDLLに対して260のwinapi 32ビットを実装。
10のDLLに対して204のwinapi 64ビットを実装。
すべてのLinuxシステムコールに対応。
SEHチェーン。
ベクタード例外ハンドラ。
PEB、TEB構造体。
動的リンク。
IATバインディング。
遅延読み込み。
メモリアロケータ。
int3による応答。
デバッグされていないcpuid。
32ビットおよび64ビットのシェルコードエミュレーション。
pe32およびpe64の実行可能ファイルのエミュレーション。
既知のペイロードを完全エミュレーション:
複雑なマルウェア関数の部分エミュレーション:
エミュレーション中に、エミュレートされたCPU命令の数(エミュレーション瞬間の一意のID)を確認できます。
-c フラグを使用すると、特定の瞬間でエミュレーションを停止し、コンソールで何が起こっているかを検査できます。
MWEMU emulator for malware 0.7.11
@sha0coder
USAGE:
mwemu [FLAGS] [OPTIONS]
FLAGS:
-6, --64bits 64ビットアーキテクチャのエミュレーションを有効にする。
--banzai 未実装の命令をスキップし、エミュレート可能なものは継続してエミュレートする。
--flags すべての命令でフラグの16進値をトレースする。
-F, --fpu FPU状態をトレースする。
-h, --handle Ctrl+Cを処理してコンソールを起動する。
--help ヘルプ情報を表示する。
-l, --loops ループの反復回数を表示する(低速)。
-m, --memory すべてのメモリアクセス(読み書き)をトレースする。
-n, --nocolors 色なしで出力し、ファイル >out にリダイレクトする。
-r, --regs 各ステップでレジスタ値を表示する。
-p, --stack_trace push/pop時のスタックをトレースする。
-t, --test テストモード。
--version バージョン情報を表示する。
-v, --verbose -vv でアセンブリ表示、-v でメッセージのみ、verboseなしではAPI呼び出しのみ表示(高速)。
OPTIONS:
-A, --args <ARGS> EXEに引数を提供する例: --args '"aa" "bb"'
--cmd <COMMAND> コンソールコマンドを実行する。
-b, --base <ADDRESS> コードのベースアドレスを設定する。
-c, --console <NUMBER> コンソールを起動するエミュレーション瞬間を選択する。
-C, --console_addr <ADDRESS> 最初のeipがアドレスに達したときにコンソールを起動する。
-d, --dump <FILE> ダンプから読み込む。
-a, --entry <ADDRESS> シェルコードのエントリポイント(デフォルトは先頭から開始)。
-e, --exit <POSITION> シェルコードの終了位置。
-f, --filename <FILE> シェルコードのバイナリファイルを指定する。
-i, --inspect <DIRECTION> メモリ監視(例: -i 'dword ptr [ebp + 0x24])
--iso <ISO> Windows ISOから本物のsystem32 DLLを抽出し、それをマップフォルダとして使用する。例: --iso ~/Downloads/win11.iso
-L, --log <LOG_FILENAME> 出力をファイルにログ出力する。
-M, --maps <PATH> メモリマップフォルダを選択する。
--mxcsr <MXCSR> mxcsrレジスタを設定する。
--r10 <R10> r10レジスタを設定する。
--r11 <R11> r11レジスタを設定する。
--r12 <R12> r12レジスタを設定する。
--r13 <R13> r13レジスタを設定する。
--r14 <R14> r14レジスタを設定する。
--r15 <R15> r15レジスタを設定する。
--r8 <R8> r8レジスタを設定する。
--r9 <R9> r9レジスタを設定する。
--rax <RAX> raxレジスタを設定する。
--rbp <RBP> rbpレジスタを設定する。
--rbx <RBX> rbxレジスタを設定する。
--rcx <RCX> rcxレジスタを設定する。
--rdi <RDI> rdiレジスタを設定する。
--rdx <RDX> rdxレジスタを設定する。
-R, --reg <REGISTER1,REGISTER2> 特定のレジスタを各ステップでトレースする(値と内容)。
--rflags <RFLAGS> rflagsレジスタを設定する。
--rsi <RSI> rsiレジスタを設定する。
--rsp <RSP> rspレジスタを設定する。
-x, --script <SCRIPT> エミュレーションスクリプトを実行する。scripts_examplesフォルダを参照。
--stack_address <ADDRESS> スタックアドレスを設定する。
-s, --string <ADDRESS> 特定のアドレスの文字列を監視する。
-T, --trace <TRACE_FILENAME> トレースを指定されたファイルに出力する。
-S, --trace_start <TRACE_START> 指定された位置からトレースを開始する。
-V, --verbose_at <NUMBER> 特定の位置からアセンブリの表示を開始する(-vvを特定の瞬間に有効にする)。
64ビットには -6 フラグが必要、-vv でASM表示、-c で特定の瞬間にコンソールを起動:
cargo run --release -- -f /tmp/shellcode.bin -6 -vv -c 19291
cargo run --release -- -f /bin/ls -6 -A '"-l"' -v
cargo run --release -- -f calc.exe -6 --winver win11
cargo run --release -- -f calc.exe -6 --winver win11 --syscall-mode
make tests
mwemuは、execve()割り込みを検出する単純なシェルコードをエミュレートします。
このツールの名前をscemuからmwemuに変更したことに注意してください(イタリア語でscemuは悪い言葉です)。

停止する行を選択し、メモリを検査します。

GuLoader win32をLinuxで200万命令近くエミュレートした後、途中でcpuid等の偽装を行い、デバッガを混乱させるsigtrapに到達します。

APIローダーでのメモリダンプの例。

デフォルトでいくつかのマップが存在し、LoadLibraryAのようなAPIまたはコンソールから手動でさらに作成できます。

LdrLoadDll()に基づく基本的なWindowsシェルコードをエミュレートし、メッセージを表示します:

コンソールを使用すると、CPUの現在の状態を表示および編集できます:
--- console ---
=>h
--- help ---
q ...................... quit
cls .................... clear screen
h ...................... help
s ...................... stack
v ...................... vars
r ...................... register show all
r reg .................. show reg
rc ..................... register change
f ...................... show all flags
fc ..................... clear all flags
fz ..................... toggle flag zero
fs ..................... toggle flag sign
c ...................... continue
ba ..................... breakpoint on address
bi ..................... breakpoint on instruction number
bmr .................... breakpoint on read memory
bmw .................... breakpoint on write memory
bc ..................... clear breakpoint
n ...................... next instruction
eip .................... change eip
push ................... push dword to the stack
pop .................... pop dword from stack
fpu .................... fpu view
md5 .................... check the md5 of a memory map
seh .................... view SEH
veh .................... view vectored execption pointer
m ...................... memory maps
ma ..................... memory allocs
mc ..................... memory create map
mn ..................... memory name of an address
ml ..................... memory load file content to map
mr ..................... memory read, speficy ie: dword ptr [esi]
mw ..................... memory read, speficy ie: dword ptr [esi] and then: 1af
md ..................... memory dump
mrd .................... memory read dwords
mds .................... memory dump string
mdw .................... memory dump wide string
mdd .................... memory dump to disk
mt ..................... memory test
ss ..................... search string
sb ..................... search bytes
sba .................... search bytes in all the maps
ssa .................... search string in all the maps
ll ..................... linked list walk
d ...................... dissasemble
dt ..................... dump structure
enter .................. step into
cobalt strikeのAPIローダーはmetasploitと同じで、エミュレートしています:

Cobalt Strike API呼び出し:

Metasploit rshell API呼び出し:

Metasploit SGNエンコーダー(多態性を隠すために少数のFPUを使用):

Metasploit shikata-ga-naiエンコーダー(こちらもFPUで開始):

PEB構造体の表示:
=>dt
structure=>peb
address=>0x7ffdf000
PEB {
reserved1: [
0x0,
0x0,
],
being_debugged: 0x0,
reserved2: 0x0,
reserved3: [
0xffffffff,
0x400000,
],
ldr: 0x77647880,
process_parameters: 0x2c1118,
reserved4: [
0x0,
0x2c0000,
0x77647380,
],
alt_thunk_list_ptr: 0x0,
reserved5: 0x0,
reserved6: 0x6,
reserved7: 0x773cd568,
reserved8: 0x0,
alt_thunk_list_ptr_32: 0x0,
reserved9: [
0x0,
...
PEB_LDR_DATA 構造体の表示:
=>dt
structure=>PEB_LDR_DATA
address=>0x77647880
PebLdrData {
length: 0x30,
initializated: 0x1,
sshandle: 0x0,
in_load_order_module_list: ListEntry {
flink: 0x2c18b8,
blink: 0x2cff48,
},
in_memory_order_module_list: ListEntry {
flink: 0x2c18c0,
blink: 0x2cff50,
},
in_initialization_order_module_list: ListEntry {
flink: 0x2c1958,
blink: 0x2d00d0,
},
entry_in_progress: ListEntry {
flink: 0x0,
blink: 0x0,
},
}
=>
LDR_DATA_TABLE_ENTRY と最初のモジュール名の表示
=>dt
structure=>LDR_DATA_TABLE_ENTRY
address=>0x2c18c0
LdrDataTableEntry {
reserved1: [
0x2c1950,
0x77647894,
],
in_memory_order_module_links: ListEntry {
flink: 0x0,
blink: 0x0,
},
reserved2: [
0x0,
0x400000,
],
dll_base: 0x4014e0,
entry_point: 0x1d000,
reserved3: 0x40003e,
full_dll_name: 0x2c1716,
reserved4: [
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
],
reserved5: [
0x17440012,
0x4000002c,
0xffff0000,
],
checksum: 0x1d6cffff,
reserved6: 0xa640002c,
time_date_stamp: 0xcdf27764,
}
=>
マルウェアが例外に何かを隠している
3307726 0x4f9673: push ebp
3307727 0x4f9674: push edx
3307728 0x4f9675: push eax
3307729 0x4f9676: push ecx
3307730 0x4f9677: push ecx
3307731 0x4f9678: push 4F96F4h
3307732 0x4f967d: push dword ptr fs:[0]
Reading SEH 0x0
-------
3307733 0x4f9684: mov eax,[51068Ch]
--- console ---
=>
例外構造体を調べてみましょう:
--- console ---
=>r esp
esp: 0x22de98
=>dt
structure=>cppeh_record
address=>0x22de98
CppEhRecord {
old_esp: 0x0,
exc_ptr: 0x4f96f4,
next: 0xfffffffe,
exception_handler: 0xfffffffe,
scope_table: PScopeTableEntry {
enclosing_level: 0x278,
filter_func: 0x51068c,
handler_func: 0x288,
},
try_level: 0x288,
}
=>
そして、ここにエラールーチン 0x4f96f4 とフィルター 0x51068c があります。