rev-unicorn-debug について
rev-unicorn-debugは、Unicornエンジンでコード断片や関数をエミュレートするスキルです。ネイティブバイナリの解析向けに、JNIやシステムコールなどの依存先をフックで再現し、障害を段階的に調べます。
主な機能
- 01対象ファイルを生バイトでマッピング
- 02フックで外部依存先を再現
- 03メモリアクセスとシステムコールを捕捉
- 04エミュレーション障害を反復して修正
- 05基本ブロック単位のトレースを優先
活用シーン
- 01バイナリ内の特定関数をエミュレート
- 02JNIやlibc呼び出しをスタブ化
- 03未マッピングメモリの障害を調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ p4nda0s/ reverse-skills --skill rev-unicorn-debugインストール後、Claude Code で/rev-unicorn-debugを入力して読み込まれたか確認します。
詳細
rev-unicorn-debug - Unicorn エミュレーションデバッガー
Unicorn エンジンを使用して、特定のコード断片や関数をデバッグおよびエミュレートします。コンテキスト依存関係(JNI、システムコール、ライブラリ関数)を分析し、フック機構を通じてシミュレートして、ユーザーのデバッグ目標を達成します。
基本原則
- まずファイルを生データとして読み込む — ELF/PE/Mach-O ヘッダーを解析しないでください。ファイルを生バイト列として読み込み、Unicorn メモリに直接マッピングします。エミュレートするのは特定の関数だけで、バイナリ全体ではありません。生データの読み込みに失敗した場合(コードが特定のアドレスにあるセグメントを参照している場合)は、最小限の解析を行い、必要なセグメントだけをマッピングしてください。
- コンテキスト依存関係を特定する — 対象コードの外部呼び出し(JNI、システムコール、libc、インポート)を分析し、シミュレートした応答を返すようフックします。
- コールバックを積極的に利用する — Unicorn のフックシステムを活用して、デバッグ、トレース、エラー復旧、環境シミュレーションを行います。
- 反復的に修正する — エミュレーションがクラッシュしたら、コールバック情報を使って原因を診断し、修正します(不足しているメモリのマッピング、未処理の呼び出しのフック、レジスタ状態の修正)。
- トレース出力は最小限にする — 命令単位のトレースより、ブロック単位のトレースを優先します。命令トレースは、対象を絞った小さな範囲でのみ有効にしてください。ステップごとのログではなく、カウンターとサマリーを使用します。
環境シミュレーション戦略
エミュレートする前に、対象関数を読み込み、呼び出している関数を特定します。外部依存関係をアドレスでフックし、Python でシミュレートします。
| カテゴリー | 例 | シミュレーション戦略 |
|---|---|---|
| libc | malloc、free、memcpy、strlen、printf | アドレスをフックし、Python で処理を実装します(malloc にはバンプアロケーターを使用) |
| JNI | GetStringUTFChars、FindClass、GetMethodID | UC メモリ内に偽の JNIEnv 関数テーブルを構築し、各エントリーに RET スタブを書き込み、スタブのアドレスをフックします |
| システムコール | read、write、mmap、ioctl | UC_HOOK_INTR をフックし、システムコール番号に応じてディスパッチします |
| C++ ランタイム | operator new、__cxa_throw | フックしてシミュレートします |
| ライブラリ呼び出し | pthread_mutex_lock、dlopen | フックし、成功を返すかスタブを返します |
フックのパターン: UC_HOOK_CODE コールバックを登録します。PC が既知のインポートアドレスに到達したら、Python でシミュレーションを実行し、PC = LR を設定して元の関数をスキップします。
使用するコールバックの種類
| コールバック | 用途 |
|---|---|
UC_HOOK_CODE | アドレスによるインポート呼び出しのインターセプト。命令単位のトレース(使用は控えめにし、範囲を狭く限定) |
UC_HOOK_BLOCK | ブロック単位のトレース(命令トレースより推奨) |
UC_HOOK_MEM_UNMAPPED | マッピングされていないアクセスエラーから復旧するため、不足しているページを自動マッピング |
UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE | 対象データ範囲のメモリアクセスのみをトレース |
UC_HOOK_INTR | システムコールシミュレーションのために SVC/INT をインターセプト |
反復デバッグのワークフロー
エミュレーションに失敗した場合は、次の手順を繰り返します。
- 実行する — エミュレーションを開始し、クラッシュさせます
- コールバック出力を読む — どのアドレスで障害が発生しましたか?種類は何ですか(読み取り/書き込み/フェッチ)?
- 診断する:
- マッピングされていないメモリのフェッチ → コードページが不足しているため、マッピングします
- マッピングされていないメモリの読み取り/書き込み → データセクションが不足しているか、ポインターが初期化されていないため、マッピングするかフックします
- インポートスタブに到達 → 関数を特定し、シミュレーション用フックを追加します
- 無限ループ → 実行カウンター付きのコードフックを追加し、しきい値に達したら停止します
- 修正する — フックを追加する/メモリをマッピングする/レジスタを調整します
- 再実行する — 対象関数が完了するまで繰り返します
Architecture Quick Reference
| Arch | Uc Const | Mode | SP | LR | Args | Return | Syscall |
|---|---|---|---|---|---|---|---|
| ARM64 | UC_ARCH_ARM64 | UC_MODE_LITTLE_ENDIAN | SP | X30 | X0-X7 | X0 | X8 + SVC #0 |
| ARM32 | UC_ARCH_ARM | UC_MODE_THUMB / UC_MODE_ARM | SP | LR | R0-R3 | R0 | R7 + SVC #0 |
| x86-64 | UC_ARCH_X86 | UC_MODE_64 | RSP | (stack) | RDI,RSI,RDX,RCX,R8,R9 | RAX | RAX + syscall |
| x86-32 | UC_ARCH_X86 | UC_MODE_32 | ESP | (stack) | (stack) | EAX | EAX + int 0x80 |
| MIPS32 | UC_ARCH_MIPS | UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN | $sp | $ra | $a0-$a3 | $v0 | $v0 + syscall |
コメント
Markdown 対応