並列IDA Proバイナリ解析、AI駆動の関数命名機能、Neo4j知識グラフ、およびphantomrtエミュレーション/フッキング/ファジングエンジンを統合し、PE、ELF、NSO形式のリバースエンジニアリングを自動化します。
バイナリを行き来するゴースト。
ローカルで動作するAI搭載リバースエンジニアリングアシスタント:並列IDA Pro解析、AIによる関数命名、ストレスのないターミナル、これまでに解析したすべてを記録するNeo4jナレッジグラフ、そしてClaudeがそのグラフを直接検索・連鎖できるMCPサーバー。
そして今や、phantomrt によって、壁を読むだけでなく、その中を歩き回れるようになりました。つまり、命名した関数をエミュレート、フック、ファジングし、実際に起きたこと をグラフに書き戻します。
✓ 00 ✓ 01 ✓ 02 ✓ 03 ▸ 04 · 05 · 06 · 07 ✓ 08 ✓ 09 ✓ 10 ✓ 11 ✓ 12 ✓ 13 ▸ 14 · 15
14/16 shards │ 141,203 functions found ████████████████████████████░░░░ 89% ~4s remaining
## 概要
IDA Proの自動解析はシングルスレッドです。34MBのil2cpp DLLでは*数分*かかります。spectrIDAはバイナリをN個のシャードに分割し、idalibを介して並列実行し、1つの`.i64`にマージした後、微調整された8Bモデルで**すべての関数に名前を付け**ます。しかも、サイバーパンクテーマと絶妙な皮肉が効いた1つのターミナルUIからすべてを実行できます。
それが第1章であり、単独で完結しています。純粋な速度向上であり、必要なければAIは不要です。
第2章では、出力をセッションを超えて存続するものに変換します。MCPクライアント(Claude、[pi](https://pi.dev)、MCPを話す任意のもの)が実際に利用できるNeo4jグラフを生成し、あなたがデコンパイラの出力を1関数ずつチャットウィンドウにコピーペーストする必要がなくなります。```
Binary ─▶ Parallel IDA Analysis ─▶ Demangle ─▶ AI Naming ─▶ Neo4j Graph ─▶ MCP Server ─▶ Claude
(N idalib shards) (free, real) (stripped (persists, (search/chain/
leftovers forever, rename, live)
only) across sessions)
第3章 (phantomrt) は、静的ツールには決してない半分の機能を追加します。それはコードを実行します。OSなしで関数をエミュレートし(起動すらできないバイナリ、例えばSwitchの.nsoでも動作)、ライブプロセスにフックしたり、ファジングしたりします。そして、その判定結果(crashes / needs live state / clean)を、名前と同じグラフノードに刻印します。
完全な詳細、まだやるべきことも含めて、第2章と第3章にあります。
これはGhidraではありません。ひとつの厄介なこと(遅い解析+命名)を高速にこなし、実際に使うのが楽しいです。199ダウンロードがそれを物語っています。
クラウドなし。テレメトリーなし。完全にあなたのマシン上で動作します。
| タスク | 時間 |
|---|---|
| Among Us DLL — シングルスレッドIDA | ~4時間 |
| Among Us DLL — spectrIDA (16ワーカー) | 67秒 |
| 153,649関数のバイナリ — 全命名パス | 一晩 |
| バイナリ概要(これは何をするものか?) | ~30秒 |
測定に使用したハードウェア: AMD Ryzen 7 5800X3D (8C/16T)、32 GB RAM、RTX 4070 12 GB。
異なるハードウェアでは並列解析の数値が変わります(コア数が多いほど、シャード数が多いほど高速になります)。命名の数値はほとんどGPUに依存します。4時間/67秒のAmong Usの数値は第2章以前のもので、すべてのリリースで独立して再検証されているわけではありません。ご自身のマシンとバイナリでの数値が必要な場合は、spectrida analyze を自分で再実行してください。結果はシャード密度とバイナリサイズによって異なります。
実際に第2章の開発中に再検証された数値(同じハードウェア):
| バイナリ | 関数 | タスク | 時間 / 結果 |
|---|---|---|---|
| test_small.dll (PE) | 189 | 並列解析、4ワーカー、CLI | 6.4s |
| test_small.dll (PE) | 164 | 完全なMCPパイプライン(解析+デマングル+グラフ書き込み) | 9.8s |
| main.nso — Mario Odyssey (NSO)、16ワーカー | 28,038 シード関数 | 並列シャードスキャンフェーズ | 54.5s |
| main.nso — Mario Odyssey (NSO)、16ワーカー | 74,790 全関数 | + マージ/完全解析フェーズ | 143.1s |
| main.nso — Mario Odyssey (NSO)、16ワーカー | 74,790 全関数 | エンドツーエンドのウォールタイム | 197.6s |
| main.nso — Mario Odyssey (NSO) | 74,790 | デマングルのみで解決(Itanium ABI、無料、AIなし) | 67,300 (90.0%) |
そのNSOの行は、以前のAmong Usの「4時間→67秒」という主張の実際の相当物であり、今回のリリースで新たに74,790関数のSwitchバイナリで測定されたものです。AI命名は関与していません(デマングルのみ — populate=False)。並列フェーズ(16コア、約55秒)は初期のシャード発見を行います。マージフェーズ(約143秒)は設計上シングルスレッドです — 1つのIDAデータベース、1つのライター — そのため、その部分でタスクマネージャーを見て15コアが休んでいるのを見ても、それはバグ報告ではなく、物理的な制約です。
ここで正直な数値を得ること自体が、ちょっとしたホラーストーリーでした。NSOサポートの最初のバージョンは正常に動作し、終了コード0で、約75,000関数あるバイナリに対して727関数を堂々と返しました。クラッシュではなく、ただ見事に、自信満々に間違っていたのです。それがなぜか悪質です。IDAにはネイティブのNSOローダーがないため、ファイルはプレーンx86("metapc")として静かにロードされました。Switchは発売当初からARM64であるにもかかわらずです。すべてのシャードは、純粋なAArch64命令に対してx86プロローグスキャナーを実行し、誤って「関数」に一致したものを何でも関数と呼びました。アーキテクチャを修正してもそれだけでは何も解決しませんでした。なぜなら、バイナリはメモリ上で依然としてLZ4圧縮されていたからです。そのため、スキャンされたものの半分は、控えめに見てもノイズでした。そして、適切に解凍され、AArch64と識別された後でも、各シャードはバイナリのごく小さなスライス内のコールターゲットのみを探し、シャード境界をまたぐすべてのコールを見逃していました。このサイズのバイナリでは、それらがほとんどです。3つのバグ、1つの数値、そしてそのどれもが例外を投げるという礼儀さえ持っていませんでした。(また、IDAのスタックフレーム解析をスキップすることでマージフェーズを短縮しようと試みました。素晴らしい高速化と、Hex-Raysがその半分の逆コンパイルを丁寧に拒否するデータベースを得ました。それはすぐに戻されました。代わりに、はるかに小さく、はるかに安全なFLIRTシグネチャスキップを保持しました。これは肩をすくめる程度の約3%の価値があり、何も壊しませんでした。この時点ではそれは維持する価値のある性格特性のように感じられました。)
命名精度について: Ghidra並みの正解率ではなく、8Bモデルが疑似コードから推測しているものです。一般的なヘルパー/ゲッターはうまく当たる傾向がありますが、ゲーム固有の深いロジックはコイン投げのようなものです。間違ったものはすべて名前を変更してください — それがrename_functionが直接グラフに反映される理由です。
.i64にマージします。ワーカーはフラグ、設定、環境変数を介して設定可能。.so/Linux) が標準搭載されています。新しいフォーマットを追加するのは単一ファイルで、コアの変更は不要です。spectrida formats で登録済みのリストを表示します。新しいバイナリフォーマットの追加 を参照。Nを押す。考えるのを見守る。名前が現れる。Bでリスト内のすべてのsub_*関数に名前を付けます。その場を離れる。戻ってくる。Oを押すか、spectrida overview file.i64を実行。モデルが120のサンプリングされた関数名を読み取り、バイナリが何をするか、サブシステムは何か、セキュリティ関連の情報を教えてくれます。153k関数のIL2CPPランタイムを30秒で正しく識別しました。Cで呼び出し元と呼び出し先を表示します。モデルはこれらを命名時のコンテキストとして使用します — Player$$TakeDamageによって呼び出される関数は、単独の場合よりも適切に名前が付けられます。DでHex-Rays疑似コードを切り替え。.idcスクリプト、またはシンボルファイルにダンプします。.idcは、AIが生成したすべての名前をワンクリックで任意のIDAインストールに適用します。from spectrida.api import open_i64。スクリプト、ノートブック、Claude CodeからTUIに触れることなくすべてを操作できます。spectrida install mcp でClaude Codeや pi に直接接続でき、手動のJSON編集は不要です。ClaudeはNeo4jバックエンドの関数グラフ(名前、疑似コード、逆アセンブリ、呼び出し元/呼び出し先)を検索/読み取り/連鎖し、新しいバイナリ自体の新鮮な解析を開始できます — analyze_binary は1つのツール呼び出しから全パイプライン(並列解析 → デマングル → AI命名 → グラフ)をバックグラウンドジョブとして実行し、ポーリングします。PEとNSOで動作します。下の第2章を参照。spectrida --demo) — ゼロセットアップですべてを試せます。IDAもOllamaも不要。pip install spectrida
必要条件: **IDA Pro 9.x** with idalib · **Python 3.10+** · **Ollama**```bash
# install Ollama (Windows)
winget install Ollama.Ollama
# pull the model (8.7 GB — go get coffee)
ollama pull hf.co/gdfhhjk/spectrida-re-gguf:latest
# first run — detects your IDA install and sets everything up
spectrida onboard
# or just try the demo right now
spectrida --demo
spectrida analyze GameAssembly.dll spectrida analyze GameAssembly.dll --workers 8 # custom worker count
spectrida open file.i64
spectrida overview file.i64 spectrida overview file.i64 --addr 0x10001000 --addr 0x10353fd0 # include specific functions
spectrida export file.i64 -f idc # IDA script — apply names to any install spectrida export file.i64 -f json # full dump with addresses + sizes spectrida export file.i64 -f csv # spreadsheet spectrida export file.i64 -f symbols # addr name pairs spectrida export file.i64 --named-only # skip sub_* functions
spectrida serve
spectrida onboard
## TUIキー
| キー | アクション |
|-----|--------|
| `N` | 選択した関数に名前を付ける — AIが結果をライブストリーミング |
| `R` | 名前変更 — AIの提案で事前入力 |
| `D` | 逆コンパイルされた擬似コードの切り替え (Hex-Rays) |
| `C` | 呼び出しチェーン — 呼び出し元と呼び出し先 |
| `B` | 現在のリスト内のすべての `sub_*` 関数を一括で命名 |
| `O` | 概要 — バイナリ全体のAI要約 |
| `/` | あいまい検索 |
| `?` | ヘルプ |
| `Q` | 終了 |
## プログラムAPI
TUIは不要 — スクリプト、Claude Code、ノートブックなどからspectrIDAを駆動:```python
import asyncio
from spectrida.api import open_i64
async def main():
async with open_i64("GameAssembly.i64") as db:
# list all 153k functions
funcs = await db.list_functions()
# name one function — returns name + reasoning + confidence
result = await db.name_function(0x10001000)
print(result["new_name"]) # init_atexit_handler
print(result["reasoning"]) # allocates array of 3 fn ptrs, calls _atexit...