IDE de ingeniería inversa agéntica con un desensamblador multiarquitectura en Rust puro, descompilador nativo, depurador y agente LLM para análisis de binarios y trabajo de CTF.
Entorno de ingeniería inversa agéntica — una aplicación de escritorio de la clase de Ghidra en el espíritu de "Cursor para ingeniería inversa". Construida con Tauri 2 (frontend en React + TypeScript) sobre un backend de análisis conectable. El predeterminado es un motor nativo en Rust puro — sin proceso externo, sin dependencia copyleft, multiarquitectura mediante Capstone. También puedes ejecutar el análisis a través de r2 (radare2): instálalo, selecciónalo como motor, y toda la aplicación — herramientas del agente e interfaz — lo controla en su lugar. La herramienta del agente y la interfaz son agnósticas al backend — consulta docs/backends.md.

Espacio de trabajo de Cargo en la raíz; la aplicación de escritorio es un paquete dentro de él.
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 es solo el agente; el análisis estático vive en recurse-static y el
depurador en recurse-debug, por lo que el agente no incorpora código de sistemas que no
utiliza. Ningún crate depende de Tauri, y cada uno se compila/prueba de forma independiente;
recurse-eval controla el agente sin interfaz. Todos son miembros del espacio de trabajo, por lo que un
Cargo.lock y un target/ cubren todo el repositorio.
Ctrl+L)checksec externo), y recuentos de análisis/clear y a la reapertura, y siembran la siguiente sesiónrecurse-agent) con trazado de depuración por turno; el mismo bucle del agente se ejecuta
en la interfaz y en el arnés de evaluaciónlift: eleva una función a un IL de desofuscación estilo VTIL y ejecuta
pases de propagación/plegado/eliminación de código muerto/resolución de ramas sobre toda la rutina
— útil cuando el desensamblado parece un despachador de VM o una cadena de
predicados opacos (consulta docs/vtil-lift.md)decompile genera pseudocódigo similar a C (estructuración de if/while,
cobertura total de instrucciones) desde el mismo pipeline de recurse-vtil
— sin herramienta externa, sin necesidad de r2recurse-mcp independiente: el mismo Engine sobre MCP stdio para cualquier
agente compatible con MCP (Claude Code, Cursor, Claude Desktop, …) — sin Tauri, sin
licencia de IDA, sin puente Python (consulta docs/recurse-mcp.md)El análisis pasa por un único trait Engine (crates/recurse-static/src/engine.rs), por lo que el
motor es una elección, no una dependencia fija:
native (predeterminado) — análisis de ELF/PE/Mach-O en Rust puro y desensamblado multiarquitectura
(object + capstone): x86/x86-64, ARM, AArch64, MIPS, PowerPC, RISC-V, SPARC, SystemZ,
M68K, BPF. Sin proceso hijo, sin herramienta externa, sin LGPL en la compilación. Incluye un descompilador
(el pipeline lift → optimize → structure de recurse-vtil — consulta
docs/vtil-lift.md) y una operación lift para desofuscación estilo VTIL.Elige con el menú de ajustes, la variable de entorno RECURSE_BACKEND, o la configuración
almacenada. El agente obtiene una única herramienta analyze neutral respecto al backend (functions, disasm, graph,
lift, decompile, xrefs, strings, imports, info, más raw para la consola del motor) —
filtrada a las operaciones que el motor activo realmente soporta, por lo que raw (el nativo no tiene consola) solo
se anuncia cuando está disponible. La interfaz consume tipos de resultado canónicos, no el JSON de ningún motor.
Consulta docs/backends.md para el trait, las elecciones de crates y la justificación
de licencias. Abrir un binario grande es rápido porque el análisis es perezoso — el descubrimiento indexa
las funciones de forma económica y los bloques básicos se decodifican solo cuando se visualiza una función; consulta
docs/lazy-analysis.md.
Enganchar un servidor MCP a IDA/Ghidra, o pegar desensamblado en un agente CLI, funciona para CTFs de 5 funciones y se desmorona con binarios reales. Recurse es un entorno hecho a propósito, no un envoltorio de chatbot:
pdF en el contexto cada turno, sin 0x401023s inventados.npm test — la verificación es
visual. Los renombrados del agente se propagan a la lista de funciones, el grafo y la descompilación
al instante, para que un humano confirme o rechace con un clic.| Herramienta | Versión (probada) | Instalación |
|---|---|---|
| Node.js | ≥ 20 (23.11 usada) | https://nodejs.org o nvm |
| npm | ≥ 10 | viene con Node.js |
| Rust | ≥ 1.77 (1.97 usada) | https://rustup.rs |
| cargo | — | viene con Rust (rustup) |
Verifica:
node --version && npm --version && rustc --version && cargo --version
El motor nativo predeterminado es Rust puro — nada que instalar. Para usar r2 (radare2)
como motor de análisis en su lugar, instálalo y selecciónalo (el menú de ajustes, o
RECURSE_BACKEND=r2); Recurse controla el binario r2 en tu PATH. r2 es opcional, nunca
es requerido por la compilación, y nunca se distribuye con Recurse — trae tu propia instalación.
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
Otras distribuciones: sigue los requisitos previos oficiales de Tauri.
Ambos motores proporcionan uno: native genera pseudocódigo mediante recurse-vtil
(lift → optimize → structure — consulta docs/vtil-lift.md),
nada que instalar; r2 puede proporcionar su propio descompilador más completo
cuando su plugin está instalado.
Las dependencias de la aplicación viven en tauri/; Rust viene de la raíz del espacio de trabajo. just envuelve
ambos (consulta just --list), o ejecútalos directamente.
just dev
# equivalent: cd tauri && npm install && npm run tauri dev
Esto inicia el servidor de desarrollo de Vite y lanza la ventana de Tauri. La primera compilación tarda un rato (compilación de Rust); las siguientes son rápidas.
just build
# equivalent: cd tauri && npm run tauri build
El paquete queda en target/release/bundle/ (target del espacio de trabajo):
.deb / .rpm / .AppImage para Linuxtarget/release/recurseEn Arch y otras distribuciones rolling el paso de AppImage necesita una corrección local única
(linuxdeploy upstream va por detrás de la cadena de herramientas de la distribución) — consulta
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
Comandos directos equivalentes: cargo clippy --workspace --all-targets,
cargo test --workspace en la raíz; npm run lint / npm run format /
npm run build dentro de tauri/.
El agente se evalúa sin interfaz contra niveles de crackme (consulta
crates/recurse-eval/README.md). Los niveles son YAML:
filtros de selección sobre el conjunto de datos, o una lista congelada de hexids, más parámetros de ejecución.
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 es un binario, no un test, por lo que cargo test nunca gasta dinero ni tiempo en
el agente. El endpoint + la clave van en crates/recurse-eval/.env (copia .env.example).
Cada ejecución escribe target/eval-traces/<tier>/<backend>/run.log (la narrativa completa)
más un <hexid>.json por tarea con la conversación completa por turno. El
backend (native o r2) es seleccionable por ejecución — consulta el README de eval.
El panel de chat del agente funciona con cualquier endpoint compatible con OpenAI. Configura la clave de API,
la URL base y el modelo desde el diálogo Model & Provider de la aplicación (persistido en
~/.recurse/recurse.db), o mediante variables de entorno:
# 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
Apunta el agente a cualquier servidor compatible con OpenAI local o autoalojado — Ollama, LM
Studio, llama-server de llama.cpp, vLLM, text-generation-webui, o una pasarela remota.
Establece la Base URL en el diálogo (tanto una URL base simple como una ruta completa /chat/completions
funcionan) y elige un modelo del catálogo de ese servidor, o escribe un id de modelo
(llama3.1:8b, qwen2.5-coder, …) directamente:
export RECURSE_LLM_ENDPOINT=http://localhost:11434/v1 # Ollama
export RECURSE_LLM_MODEL=llama3.1:8b
export RECURSE_LLM_API_KEY= # usually unnecessary locally
Los endpoints locales no necesitan clave de API: cuando la clave está vacía, la solicitud se envía sin
cabecera Authorization, y la lista de modelos se lee del propio {base}/models del endpoint.
Un endpoint personalizado se considera configurado sin clave, por lo que el
chat funciona directamente contra un servidor local.
Sin credenciales, recurre a un cliente de eco para que el cableado siga siendo ejercitable.
El agente ve el contexto del binario en vivo (arquitectura, bits, tipo) y puede controlar toda la superficie de análisis (desensamblado, xrefs, strings, imports, descompilación) a través de la sesión.
Apache-2.0 — © 2026 Aayush Khanna