Agentische Reverse-Engineering-IDE mit einem reinen Rust-Multi-Architektur-Disassembler, nativem Decompiler, Debugger und LLM-Agenten für Binäranalyse und CTF-Arbeit.
Agentische Reverse-Engineering-Umgebung — eine Desktop-App der Ghidra-Klasse im Geiste von „Cursor für Reverse Engineering". Gebaut mit Tauri 2 (React + TypeScript-Frontend) auf einem austauschbaren Analyse-Backend. Der Standard ist eine reine Rust-Engine — kein externer Prozess, keine Copyleft-Abhängigkeit, Multi-Architektur über Capstone. Du kannst die Analyse auch über r2 (radare2) laufen lassen: installiere es, wähle es als Engine, und die gesamte App — Agent-Tools und UI — steuert es stattdessen. Das Agent-Tool und die UI sind backend-agnostisch — siehe docs/backends.md.

Cargo-Workspace im Root; die Desktop-App ist ein Paket darin.
tauri/ desktop app (Tauri + React)
src/ React frontend
src-tauri/ Tauri Rust backend (engine sessions, agent wiring)
package.json app scripts (Vite, Vitest, Tauri CLI)
crates/
recurse-agent/ agent framework: LLM loop, tool runtime, SQLite memory
recurse-static/ static analysis: ELF/PE/Mach-O parsing, multi-arch disassembly,
CFG and cross-reference recovery, the engine seam
recurse-vtil/ VTIL-inspired de-obfuscation/de-virtualization IL, lifter, optimizer
recurse-mcp/ standalone headless MCP server (stdio) over the engine — no Tauri, no IDA
recurse-debug/ cross-platform debugger (ptrace/Mach/Win32, breakpoints, stepping)
recurse-eval/ headless eval harness (YAML-configured tiers)
justfile single entry point for both halves
recurse-agent ist nur der Agent; die statische Analyse lebt in recurse-static und der
Debugger in recurse-debug, sodass der Agent weder Systemcode einbindet, den er nicht
verwendet. Kein Crate hängt von Tauri ab, und jedes lässt sich eigenständig bauen/testen;
recurse-eval steuert den Agent headless. Alle sind Workspace-Mitglieder, sodass ein
Cargo.lock und ein target/ das gesamte Repo abdecken.
Ctrl+L)checksec), und Analyse-Zähler/clear und erneutes Öffnen und befüllen die nächste Sessionrecurse-agent) mit Debug-Tracing pro Turn; dieselbe Agent-Schleife läuft
in der UI und im Eval-Harnesslift-Op: hebt eine Funktion in eine VTIL-artige De-Obfuskierungs-IL und führt
Propagation/Folding/Dead-Code-Elimination/Branch-Resolution-Pässe über die gesamte
Routine aus — nützlich, wenn die Disassembly wie ein VM-Dispatcher oder eine
Opaque-Predicate-Kette aussieht (siehe docs/vtil-lift.md)decompile rendert C-ähnlichen Pseudocode (if/while-
Strukturierung, vollständige Instruktionsabdeckung) aus derselben recurse-vtil-
Pipeline — kein externes Tool, kein r2 erforderlichrecurse-mcp-Server: dieselbe Engine über MCP stdio für jeden
MCP-fähigen Agent (Claude Code, Cursor, Claude Desktop, …) — kein Tauri, kein
IDA-Seat, keine Python-Bridge (siehe docs/recurse-mcp.md)Die Analyse läuft über ein einziges Engine-Trait (crates/recurse-static/src/engine.rs), sodass die
Engine eine Wahl ist, keine harte Abhängigkeit:
native (Standard) — reines Rust-Parsing von ELF/PE/Mach-O und Multi-Architektur-Disassembly
(object + capstone): x86/x86-64, ARM, AArch64, MIPS, PowerPC, RISC-V, SPARC, SystemZ,
M68K, BPF. Kein Kindprozess, kein externes Tool, kein LGPL im Build. Enthält einen Decompiler
(die Lift → Optimize → Structure-Pipeline von recurse-vtil — siehe
docs/vtil-lift.md) und eine lift-Op für VTIL-artige De-Obfuskierung.Auswählbar über das Einstellungsmenü, die Umgebungsvariable RECURSE_BACKEND oder die gespeicherte
Konfiguration. Der Agent erhält ein backend-neutrales analyze-Tool (functions, disasm, graph,
lift, decompile, xrefs, strings, imports, info, plus raw für die Engine-Konsole) —
gefiltert auf die Ops, die die aktive Engine tatsächlich unterstützt, sodass raw (native hat keine Konsole)
nur angeboten wird, wenn verfügbar. Die UI konsumiert kanonische Ergebnistypen, nicht das JSON irgendeiner Engine.
Siehe docs/backends.md für das Trait, die Crate-Entscheidungen und die Lizenz-
Begründung. Das Öffnen einer großen Binärdatei ist schnell, weil die Analyse lazy ist — die Discovery indexiert
Funktionen kostengünstig und Basic Blocks werden erst dekodiert, wenn eine Funktion angezeigt wird; siehe
docs/lazy-analysis.md.
Einen MCP-Server an IDA/Ghidra zu kleben oder Disassembly in einen CLI-Agent einzufügen, funktioniert für 5-Funktions-CTFs und scheitert bei echten Binärdateien. Recurse ist eine zweckgebaute Umgebung, kein Chatbot-Wrapper:
pdF-Dumps in den Kontext bei jedem Turn, keine erfundenen 0x401023s.npm test — Verifikation ist
visuell. Agent-Umbenennungen propagieren sofort in Funktionsliste, Graph und Decompile,
sodass ein Mensch mit einem Klick bestätigt oder ablehnt.| Tool | Version (getestet) | Installation |
|---|---|---|
| Node.js | ≥ 20 (23.11 verwendet) | https://nodejs.org oder nvm |
| npm | ≥ 10 | wird mit Node.js ausgeliefert |
| Rust | ≥ 1.77 (1.97 verwendet) | https://rustup.rs |
| cargo | — | wird mit Rust (rustup) ausgeliefert |
Überprüfen:
node --version && npm --version && rustc --version && cargo --version
Die standardmäßige native Engine ist reines Rust — nichts zu installieren. Um stattdessen r2 (radare2)
als Analyse-Engine zu verwenden, installiere es und wähle es aus (das Einstellungsmenü oder
RECURSE_BACKEND=r2); Recurse steuert die r2-Binärdatei in deinem PATH. r2 ist optional, wird
vom Build niemals benötigt und niemals mit Recurse verteilt — bring deine eigene Installation mit.
Debian/Ubuntu/Pop!_OS:
sudo apt update
sudo apt install -y libwebkit2gtk-4.1-dev build-essential \
curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
Andere Distributionen: folge den offiziellen Tauri-Voraussetzungen.
Beide Engines bieten einen: native rendert Pseudocode über recurse-vtil
(Lift → Optimize → Structure — siehe docs/vtil-lift.md),
nichts zu installieren; r2 kann seinen eigenen, vollständigeren Decompiler bereitstellen,
wenn sein Plugin installiert ist.
App-Abhängigkeiten liegen in tauri/; Rust kommt aus dem Workspace-Root. just umschließt
beide (siehe just --list), oder steuere sie direkt.
just dev
# equivalent: cd tauri && npm install && npm run tauri dev
Dies startet den Vite-Dev-Server und öffnet das Tauri-Fenster. Die erste Kompilierung dauert eine Weile (Rust-Build); nachfolgende sind schnell.
just build
# equivalent: cd tauri && npm run tauri build
Das Bundle landet in target/release/bundle/ (Workspace-Target):
.deb / .rpm / .AppImage für Linuxtarget/release/recurseAuf Arch und anderen Rolling-Distributionen benötigt der AppImage-Schritt einen einmaligen lokalen Fix
(upstream linuxdeploy hinkt der Distro-Toolchain hinterher) — siehe
docs/linux-appimage-build.md.
just preview
# equivalent: cd tauri && npm run build && npm run preview
just lint # cargo clippy --workspace + eslint
just fmt # cargo fmt --all + prettier
just fmt-check # verify without writing
just test # cargo test --workspace + vitest
Äquivalente direkte Befehle: cargo clippy --workspace --all-targets,
cargo test --workspace im Root; npm run lint / npm run format /
npm run build innerhalb von tauri/.
Der Agent wird headless gegen Crackme-Tiers evaluiert (siehe
crates/recurse-eval/README.md). Tiers sind YAML:
Auswahlfilter über das Dataset oder eine eingefrorene Hexid-Liste, plus Run-Knobs.
just eval-fetch # download the tier's binaries
just eval-test # harness self-tests (no API key needed, no LLM calls)
just eval-run # run the tier — the only way to execute an eval YAML
eval-run ist eine Binärdatei, kein Test, sodass cargo test niemals Geld oder Zeit für
den Agent ausgibt. Endpunkt + Key gehören in crates/recurse-eval/.env (kopiere .env.example).
Jeder Lauf schreibt target/eval-traces/<tier>/<backend>/run.log (die vollständige Narration)
plus eine <hexid>.json pro Task mit der vollständigen Konversation pro Turn. Das
Backend (native oder r2) ist pro Lauf auswählbar — siehe das Eval-README.
Das Agent-Chat-Panel läuft auf jedem OpenAI-kompatiblen Endpunkt. Konfiguriere den API-Key,
die Base-URL und das Modell über den In-App-Dialog Model & Provider (persistiert in
~/.recurse/recurse.db) oder über Env:
# Hosted provider (default)
export RECURSE_LLM_API_KEY=sk-or-... # or OPENROUTER_API_KEY
export RECURSE_LLM_ENDPOINT=https://openrouter.ai/api/v1/chat/completions # optional
export RECURSE_LLM_MODEL=openrouter/auto # optional
Richte den Agent auf jeden lokalen oder selbst gehosteten OpenAI-kompatiblen Server — Ollama, LM
Studio, llama.cpps llama-server, vLLM, text-generation-webui oder ein Remote-Gateway.
Setze die Base URL im Dialog (eine bloße Base-URL oder eine vollständige /chat/completions-
Route funktionieren beide) und wähle ein Modell aus dem Katalog dieses Servers oder gib eine Modell-ID
(llama3.1:8b, qwen2.5-coder, …) direkt ein:
export RECURSE_LLM_ENDPOINT=http://localhost:11434/v1 # Ollama
export RECURSE_LLM_MODEL=llama3.1:8b
export RECURSE_LLM_API_KEY= # usually unnecessary locally
Lokale Endpunkte benötigen keinen API-Key: wenn der Key leer ist, wird die Anfrage ohne
Authorization-Header gesendet, und die Modellliste wird aus dem eigenen
{base}/models des Endpunkts gelesen. Ein benutzerdefinierter Endpunkt gilt als ohne Key konfiguriert, sodass der
Chat gegen einen lokalen Server sofort funktioniert.
Ohne Credentials fällt es auf einen Echo-Client zurück, damit die Verdrahtung weiterhin testbar bleibt.
Der Agent sieht Live-Binärkontext (Arch, Bits, Typ) und kann die vollständige Analyse- Oberfläche (Disassembly, Xrefs, Strings, Imports, Decompilation) durch die Session steuern.
Apache-2.0 — © 2026 Aayush Khanna