reverse-engineering について
ソースコードのないバイナリーを初期調査から逆コンパイル、比較まで分析するためのエージェント向けスキルです。Ghidra、radare2、Binary Ninjaのスクリプト、C++パターン認識、シンボル除去済みバイナリーの解析を扱います。
主な機能
- 01コマンドラインツールによる初期調査
- 02Ghidraの逆コンパイルとスクリプト
- 03radare2による解析とパッチ
- 04Binary Ninjaスクリプト
- 05C++とシンボル除去済みバイナリーの解析
- 06バイナリー差分の比較
活用シーン
- 01未知の実行ファイルの調査
- 02コンパイル済みソフトウェアからロジックを復元
- 03ファームウェアの版を比較してパッチを確認
- 04マルウェアやCTFバイナリーの解析
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill reverse-engineeringインストール後、Claude Code で/reverse-engineeringを入力して読み込まれたか確認します。
詳細
リバースエンジニアリング
目的
バイナリのリバースエンジニアリングをエージェントに案内します。Ghidra のプロジェクト設定と逆コンパイル、radare2 の分析ワークフロー、Binary Ninja のスクリプト作成、strings/file/xxd を使った初期トリアージ、C++ パターン(vtable、RAII)の特定、シンボルが削除されたバイナリの分析、Diaphora または BinDiff による差分比較を扱います。
使用する場面
- ソースコードのない未知のバイナリを分析する
- コンパイル済み実行ファイルからアルゴリズムのロジックを復元する
- 2 つのファームウェアのバージョンを比較して、脆弱性の修正を確認する
- マルウェアや CTF チャレンジのバイナリを理解する
- シンボルが削除された ELF/PE ファイルからシンボルを復元する
- Ghidra または r2 のスクリプトで分析を自動化する
ワークフロー
1. 初期トリアージ
file suspicious_binary
strings -n 8 suspicious_binary | head -50
strings -el suspicious_binary # UTF-16 LE
xxd suspicious_binary | head -20
readelf -h suspicious_binary # ELF
objdump -d -M intel suspicious_binary | head -40
# Check protections
checksec --file=suspicious_binary
| コマンド | 判明する情報 |
|---|---|
file | アーキテクチャ、静的リンク/動的リンク、シンボル削除の有無 |
strings | URL、パス、エラーメッセージ、キー |
readelf -s | シンボルテーブル(シンボルが削除されていない場合) |
nm -D | 動的シンボル |
checksec | RELRO、NX、PIE、カナリア |
2. Ghidra のワークフロー
# Headless analysis
analyzeHeadless /tmp/ghidra_projects MyProject \
-import suspicious_binary \
-postScript ExportDecompile.java
# GUI: File → New Project → Import File → Analyze (Yes)
主な手順:
- 自動分析 — Ghidra で逆アセンブルを完了します
- 関数の定義 — エントリーポイントで関数が検出されていない場合は
Fを押します - デコンパイラー — Window → Decompiler(C に似た出力)
- 名前の変更 — 変数や関数をわかりやすくするには、それらを選択して
Lを押します - クロスリファレンス — 関数やデータを選択して
Ctrl+Shift+Fを押します
// Ghidra script (Java) — list functions > 100 bytes
import ghidra.program.model.listing.*;
FunctionManager fm = currentProgram.getFunctionManager();
for (Function f : fm.getFunctions(true)) {
if (f.getBody().getNumAddresses() > 100)
println(f.getName() + " @ " + f.getEntryPoint());
}
# Ghidra Python (Jython)
from ghidra.program.model.listing import FunctionManager
fm = currentProgram.getFunctionManager()
for f in fm.getFunctions(True):
print(f.getName(), f.getEntryPoint())
3. radare2 のワークフロー
r2 suspicious_binary
[0x00001000]> aaa # analyze all
[0x00001000]> afl # list functions
[0x00001000]> pdf @ main # disassemble function
[0x00001000]> VV # visual graph mode
[0x00001000]> iz # strings in data sections
[0x00001000]> s sym.main; pdf
パッチ適用:
[0x00001000]> wx 9090 @ 0x401234 # write NOPs
[0x00001000]> wci 0x401234 # insert instruction
[0x00001000]> wt modified_binary
# r2 scripting
r2 -qc 'aaa; afl' suspicious_binary
r2 -i analysis.r2 suspicious_binary
4. Binary Ninja のスクリプト作成
# BN Python API
import binaryninja as bn
bv = bn.load("suspicious_binary")
for func in bv.functions:
if func.name.startswith("sub_"):
hlil = func.hlil
for block in hlil:
print(block)
5. C++ パターンの認識
// Vtable pattern in disassembly
// mov rax, [rdi] ; load vtable pointer
// call [rax+0x10] ; virtual call at offset
// Constructor pattern
// mov [obj], offset vtable
| パターン | 特徴 |
|---|---|
| Vtable | .data.rel.ro セクション、関数ポインターの配列 |
| RAII | コンストラクター/デストラクターの対になった呼び出し、例外処理のランディングパッド |
| テンプレート | マングルされた名前 _Z...、型ごとに重複するロジック |
| std::string | インラインの SSO バッファー、またはオフセット 0 にあるヒープポインター |
# Demangle C++ symbols
c++filt _ZN4Math3addEii
6. シンボルが削除されたバイナリの復元
# Find main via __libc_start_main
readelf -s binary | grep -E 'main|start'
# Or r2: afl~entry
# FLIRT signatures (Ghidra/BN) — match libc patterns
# Stack string analysis in Ghidra decompiler
方針:
- libc の初期化処理またはエントリーポイントを手掛かりに
mainを特定する - システムコールを探す(Linux では
syscall命令) - 文字列のクロスリファレンスからエラーハンドラーを特定する
- エントロピー分析で暗号化されたセクションを探す
7. バイナリの差分比較
# Diaphora (Ghidra/IDA plugin)
# Export from both binaries, run diff
# BinDiff (commercial, IDA/Ghidra)
bindiff old.i64 new.i64
# Simple hash diff
sha256sum firmware_v1 firmware_v2
diff <(objdump -d v1) <(objdump -d v2) | head
更新後に修正された脆弱性関連の関数を見つけるには、差分比較を使用します。
8. RE の判断フローチャート
Binary type?
├── ELF/Linux → Ghidra + r2 + readelf
├── PE/Windows → Ghidra + PE-bear + x64dbg reference
├── Firmware → binwalk extract → Ghidra on architecture
└── Obfuscated → dynamic analysis (gdb/ltrace) first
よくある問題
| 症状 | 原因 | 修正方法 |
|---|---|---|
| Ghidra のデコンパイラーが失敗する | 間接ジャンプ、不正な型 | 関数シグネチャを修正し、構造体を定義します |
| r2 の分析が不完全 | バイナリが大きい | aaa の後に aac を実行し、分析の深さを増やします |
| アーキテクチャが誤っている | ARM と Thumb の違い、MIPS | -a arm を指定するか、正しい Ghidra 言語を設定します |
| アンチデバッグのトラップ | ptrace チェック | パッチを適用するか、QEMU で -gdb を使用します |
| パックされたバイナリ | UPX など | upx -d または手動でアンパックします |
| 文字列への xref がない | PIE/RELRO | GOT をたどるか、実行時分析を行います |
関連スキル
skills/binaries/elf-inspection— ELF 構造の分析skills/debuggers/gdb— 動的分析を補完skills/runtimes/binary-hardening— バイパス対象となる緩和策の理解skills/security/kernel-security— カーネルのリバースエンジニアリングと CVE 分析skills/low-level-programming/assembly-x86— 逆アセンブル結果の読み方skills/low-level-programming/assembly-arm— ARM バイナリの分析
コメント
Markdown 対応