IDE d'ingénierie inverse agentique avec un désassembleur multi-architecture en pur Rust, un décompilateur natif, un débogueur et un agent LLM pour l'analyse binaire et le travail CTF.
Environnement d'ingénierie inverse agentique — une application de bureau de la classe Ghidra dans l'esprit de « Cursor pour l'ingénierie inverse ». Construit avec Tauri 2 (frontend React + TypeScript) au-dessus d'un backend d'analyse enfichable. Par défaut, il s'agit d'un moteur natif pur Rust — aucun processus externe, aucune dépendance copyleft, multi-architecture via Capstone. Vous pouvez également exécuter l'analyse via r2 (radare2) : installez-le, sélectionnez-le comme moteur, et toute l'application — outils de l'agent et interface — le pilote à la place. L'outil de l'agent et l'interface sont agnostiques du backend — voir docs/backends.md.

Espace de travail Cargo à la racine ; l'application de bureau est l'un de ses paquets.
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 n'est que l'agent ; l'analyse statique réside dans recurse-static et le
débogueur dans recurse-debug, de sorte que l'agent n'embarque aucun code système qu'il
n'utilise pas. Aucun crate ne dépend de Tauri, et chacun se compile/se teste de manière autonome ;
recurse-eval pilote l'agent sans interface. Tous sont membres de l'espace de travail, donc un seul
Cargo.lock et un seul target/ couvrent tout le dépôt.
Ctrl+L)checksec externe), et compteurs d'analyse/clear et à la réouverture, et amorcent la session suivanterecurse-agent) avec traçage de débogage par tour ; la même boucle d'agent s'exécute
dans l'interface et dans le harnais d'évaluationlift : élève une fonction vers un IL de désobfuscation de style VTIL et exécute
sur toute la routine des passes de propagation/repliement/élimination de code mort/résolution de branchement
— utile lorsque le désassemblage ressemble à un dispatcheur de VM ou à une chaîne
de prédicats opaques (voir docs/vtil-lift.md)decompile produit du pseudocode de type C (if/while
structurés, couverture totale des instructions) à partir du même pipeline recurse-vtil
— aucun outil externe, r2 non requisrecurse-mcp autonome : le même Engine via MCP stdio pour tout
agent compatible MCP (Claude Code, Cursor, Claude Desktop, …) — pas de Tauri, pas de
licence IDA, pas de pont Python (voir docs/recurse-mcp.md)L'analyse passe par un unique trait Engine (crates/recurse-static/src/engine.rs), donc le
moteur est un choix, pas une dépendance dure :
native (par défaut) — analyse ELF/PE/Mach-O en pur Rust et désassemblage multi-architecture
(object + capstone) : x86/x86-64, ARM, AArch64, MIPS, PowerPC, RISC-V, SPARC, SystemZ,
M68K, BPF. Aucun processus enfant, aucun outil externe, aucun LGPL dans la compilation. Inclut un décompilateur
(pipeline lift → optimize → structure de recurse-vtil — voir
docs/vtil-lift.md) et une opération lift pour la désobfuscation de style VTIL.Choisissez via le menu des paramètres, la variable d'environnement RECURSE_BACKEND, ou la
configuration stockée. L'agent dispose d'un unique outil analyze neutre vis-à-vis du backend (functions, disasm, graph,
lift, decompile, xrefs, strings, imports, info, plus raw pour la console du moteur) —
filtré selon les opérations réellement prises en charge par le moteur actif, donc raw (le natif n'a pas de console) n'est
annoncé que lorsqu'il est disponible. L'interface consomme des types de résultats canoniques, pas le JSON d'un moteur.
Voir docs/backends.md pour le trait, les choix de crates, et la justification
de licence. L'ouverture d'un gros binaire est rapide car l'analyse est paresseuse — la découverte indexe
les fonctions à moindre coût et les blocs de base ne sont décodés que lorsqu'une fonction est consultée ; voir
docs/lazy-analysis.md.
Greffer un serveur MCP sur IDA/Ghidra, ou coller du désassemblage dans un agent CLI, fonctionne pour des CTF de 5 fonctions et s'effondre sur de vrais binaires. Recurse est un environnement conçu sur mesure, pas un habillage de chatbot :
pdF dans le contexte à chaque tour, pas de 0x401023 inventés.npm test — la vérification est
visuelle. Les renommages de l'agent se propagent à la liste de fonctions, au graphe et à la décompilation
instantanément, donc un humain confirme ou rejette en un clic.| Outil | Version (testée) | Installation |
|---|---|---|
| Node.js | ≥ 20 (23.11 utilisée) | https://nodejs.org ou nvm |
| npm | ≥ 10 | fourni avec Node.js |
| Rust | ≥ 1.77 (1.97 utilisée) | https://rustup.rs |
| cargo | — | fourni avec Rust (rustup) |
Vérifier :
node --version && npm --version && rustc --version && cargo --version
Le moteur native par défaut est du pur Rust — rien à installer. Pour utiliser r2 (radare2)
comme moteur d'analyse à la place, installez-le et sélectionnez-le (le menu des paramètres, ou
RECURSE_BACKEND=r2) ; Recurse pilote le binaire r2 présent dans votre PATH. r2 est optionnel, n'est
jamais requis par la compilation, et n'est jamais distribué avec Recurse — apportez votre propre installation.
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
Autres distributions : suivez les prérequis Tauri officiels.
Les deux moteurs en fournissent un : native produit du pseudocode via recurse-vtil
(lift → optimize → structure — voir docs/vtil-lift.md),
rien à installer ; r2 peut fournir son propre décompilateur plus complet
lorsque son plugin est installé.
Les dépendances de l'application résident dans tauri/ ; Rust vient de la racine de l'espace de travail. just encapsule
les deux (voir just --list), ou pilotez-les directement.
just dev
# equivalent: cd tauri && npm install && npm run tauri dev
Cela démarre le serveur de développement Vite et lance la fenêtre Tauri. La première compilation prend un certain temps (build Rust) ; les suivantes sont rapides.
just build
# equivalent: cd tauri && npm run tauri build
Le paquet atterrit dans target/release/bundle/ (cible de l'espace de travail) :
.deb / .rpm / .AppImage pour Linuxtarget/release/recurseSur Arch et autres distributions rolling, l'étape AppImage nécessite une correction locale unique
(le linuxdeploy amont est en retard sur la chaîne d'outils de la distribution) — voir
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
Commandes directes équivalentes : cargo clippy --workspace --all-targets,
cargo test --workspace à la racine ; npm run lint / npm run format /
npm run build dans tauri/.
L'agent est évalué sans interface contre des niveaux de crackme (voir
crates/recurse-eval/README.md). Les niveaux sont en YAML :
filtres de sélection sur le jeu de données, ou une liste d'hexid figée, plus des réglages d'exécution.
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 est un binaire, pas un test, donc cargo test ne dépense jamais d'argent ni de temps sur
l'agent. Le point de terminaison + la clé vont dans crates/recurse-eval/.env (copiez .env.example).
Chaque exécution écrit target/eval-traces/<tier>/<backend>/run.log (le récit complet)
plus un <hexid>.json par tâche avec la conversation complète par tour. Le
backend (native ou r2) est sélectionnable par exécution — voir le README d'évaluation.
Le panneau de chat de l'agent fonctionne sur tout point de terminaison compatible OpenAI. Configurez la clé API,
l'URL de base, et le modèle depuis la boîte de dialogue Model & Provider dans l'application (persistée dans
~/.recurse/recurse.db), ou via l'environnement :
# 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
Pointez l'agent vers n'importe quel serveur compatible OpenAI local ou auto-hébergé — Ollama, LM
Studio, llama-server de llama.cpp, vLLM, text-generation-webui, ou une passerelle distante.
Définissez l'URL de base dans la boîte de dialogue (une URL de base nue ou une route complète /chat/completions
fonctionnent toutes les deux) et choisissez un modèle dans le catalogue de ce serveur, ou saisissez un identifiant de modèle
(llama3.1:8b, qwen2.5-coder, …) directement :
export RECURSE_LLM_ENDPOINT=http://localhost:11434/v1 # Ollama
export RECURSE_LLM_MODEL=llama3.1:8b
export RECURSE_LLM_API_KEY= # usually unnecessary locally
Les points de terminaison locaux ne nécessitent aucune clé API : lorsque la clé est vide, la requête est envoyée sans
en-tête Authorization, et la liste des modèles est lue depuis le {base}/models du point de terminaison lui-même.
Un point de terminaison personnalisé est considéré comme configuré sans clé, donc le
chat fonctionne immédiatement contre un serveur local.
Sans identifiants, il retombe sur un client echo pour que le câblage reste exerçable.
L'agent voit le contexte binaire en direct (arch, bits, type) et peut piloter toute la surface d'analyse (désassemblage, xrefs, chaînes, imports, décompilation) à travers la session.
Apache-2.0 — © 2026 Aayush Khanna