
Ingeniería inversa asistida por IA con Ghidra
Rev·Deck es una estación de trabajo local de análisis estático para un solo usuario. Combina una interfaz web basada en evidencias con un copiloto de LLM sobre un binario analizado por un servicio Ghidra sin cabeza: navegue directamente por las evidencias deterministas (funciones, cadenas, importaciones, referencias cruzadas, un grafo de llamadas acotado), o haga preguntas acotadas al asistente cuyas afirmaciones fácticas deben citar evidencias inspeccionables.
Los binarios analizados nunca se ejecutan. El navegador solo se comunica con esta aplicación Flask; la aplicación proxy valida y tipifica las solicitudes al servicio Ghidra.
https://github.com/user-attachments/assets/fba14dc5-7ad5-4137-9349-ed824da64fbe
cp .env.example .env # set API_BASE and MODEL_NAME; set API_KEY if required
docker compose up --build
Docker Compose lee .env automáticamente para la interpolación. Fallará al iniciar si falta API_BASE o MODEL_NAME; API_KEY=not-used sigue siendo válida para proveedores locales/sin clave. El stack inicia ambos servicios. Abra http://127.0.0.1:5000.
Para ejecutar solo el servicio Ghidra:
docker pull biniamfd/ghidra-headless-rest:latest # ensure the newest image
docker run --rm \
-p 127.0.0.1:9090:9090 \
-v "$(pwd)/data:/data/ghidra_projects" \
--security-opt no-new-privileges:true \
biniamfd/ghidra-headless-rest:latest
Para un pin reproducible, use el digest de la versión probada en lugar de latest:
docker run --rm \
-p 127.0.0.1:9090:9090 \
-v "$(pwd)/data:/data/ghidra_projects" \
--security-opt no-new-privileges:true \
biniamfd/ghidra-headless-rest:1.2.1@sha256:971591a3a8448d8ed969079b452306e806f36079c3ddd298f4a618d6e2f1442d
biniamfd/ghidra-headless-rest:latest.Copie .env.example a .env y complete estas; consulte ese archivo para la lista completa y los valores predeterminados.
Rev·Deck se comunica con cualquier endpoint de Chat Completions compatible con OpenAI a través del SDK de OpenAI, configurado completamente por API_BASE / API_KEY / MODEL_NAME. No hay lógica de cabecera, parámetro o modelo específica del proveedor: un servidor local Ollama (API_BASE=http://127.0.0.1:11434/v1), un endpoint vLLM/llama.cpp/LM Studio autoalojado, el propio OpenAI, o una puerta de enlace como OpenRouter funcionan de la misma manera.
Ejemplos de configuración de proveedor en .env (use marcadores de posición, nunca confíe claves reales):
# Ollama
API_BASE=http://127.0.0.1:11434/v1
API_KEY=not-used
MODEL_NAME=qwen3:8b
# OpenRouter
API_BASE=https://openrouter.ai/api/v1
API_KEY=replace-with-your-key
MODEL_NAME=anthropic/claude-opus-4.8
# OpenAI
API_BASE=https://api.openai.com/v1
API_KEY=replace-with-your-key
MODEL_NAME=replace-with-a-supported-model-id
# LM Studio, vLLM, or llama.cpp (adjust port/model to the server)
API_BASE=http://127.0.0.1:1234/v1
API_KEY=not-used
MODEL_NAME=replace-with-the-served-model-id
Por defecto (LLM_STREAM=auto) el asistente solicita una respuesta streamed y retransmite los tokens al navegador a medida que llegan. El streaming también ofrece una garantía de cancelación más fuerte: cuando se detiene una respuesta (o se cierra la pestaña), Rev·Deck cierra rápidamente el flujo del proveedor subyacente y no realiza más rondas de herramientas o modelos, por lo que la generación ascendente se interrumpe en lugar de dejarse ejecutar hasta completarse en segundo plano.
Advertencias:
auto, si el proveedor rechaza la solicitud streamed con un error de compatibilidad (HTTP 400/404/405/422) antes de cualquier salida de contenido o llamada a herramienta, Rev·Deck retrocede a una única llamada bloqueante una vez y lo recuerda durante el resto del proceso. Los errores de autenticación (401/403), límite de tasa (429) y de servidor (5xx) no se tratan como problemas de compatibilidad y se muestran como errores en lugar de reintentarlos silenciosamente. Establezca LLM_STREAM=false para omitir el streaming por completo, o LLM_STREAM=true para requerirlo (sin retroceso).Abra la aplicación y cargue un binario para iniciar un trabajo de análisis. El texto plano obvio solicita confirmación antes de enviarse a Ghidra; use la anulación explícita de binario sin formato solo cuando el contenido sea intencionalmente firmware/datos en lugar de un formato ejecutable. Una vez completado el análisis, cambie entre dos pestañas del espacio de trabajo:
Ambos modos toman un presupuesto de pasos por tarea, y una opción Sin límite de pasos que se ejecuta hasta que la tarea finaliza (todavía limitada por MAX_STEP_BUDGET para que un modelo en bucle no pueda descontrolarse). Si una ejecución alcanza su presupuesto, reporta resultados parciales y ofrece Continuar — que reanuda la misma conversación usando las evidencias ya recuperadas, sin rehacer las llamadas a herramientas completadas. El costo crece con el número de llamadas a herramientas/modelos, por lo que presupuestos más altos cuestan más.
Flujos de trabajo disponibles:
Cada trabajo de análisis tiene un chat Principal más opcionales subhilos enfocados. Elija Nueva subinvestigación, ingrese un resumen de una línea y trabaje con un contexto de conversación fresco sobre el mismo binario y las mismas herramientas de solo lectura. Los historiales de los hilos permanecen aislados, y solo un hilo transmite a la vez.
Cuando el trabajo enfocado esté listo, elija Devolver conclusión al padre. Rev·Deck realiza una llamada de modelo acotada solo sobre ese subhilo, valida sus citas de evidencia y agrega una tarjeta de conclusión marcada con procedencia al padre. La rama completa permanece reabrible, mientras que el contexto padre recibe solo la conclusión compacta—no la transcripción de la rama. Una tarjeta devuelta sin citas validadas se marca explícitamente como no verificada.
Las respuestas del asistente citan evidencias en línea como [function:0xADDR], [string:0xADDR] o [import:name]. Las citas se verifican contra lo que realmente se recuperó durante el turno; una cita que no coincide se marca como "(no verificada)" y debe tratarse como una afirmación no confirmada, no como un hecho.
Los diagramas Mermaid en la salida del asistente (por ejemplo, bocetos de grafos de llamadas) se renderizan en un marco aislado sin acceso a la red externa.
El navegador se comunica solo con la aplicación web Rev·Deck. Rev·Deck coordina el LLM configurado y el servicio Ghidra sin cabeza, y luego presenta la evidencia resultante y la actividad del agente en un solo espacio de trabajo.
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
npm ci && npm run vendor # one-time: vendors the pinned Mermaid runtime
cp .env.example .env # edit API_BASE / MODEL_NAME / API_KEY
set -a; source .env; set +a # plain Python does not load .env automatically
# Start the separate Ghidra service, then:
python webui/app.py
Abra http://127.0.0.1:5000. Docker Compose lee .env automáticamente; la ejecución desde el código fuente requiere exportarlo como se muestra arriba. El servidor de desarrollo Flask es adecuado para uso local; la imagen Docker ejecuta Gunicorn.
Está diseñado para un analista de confianza en su propia máquina, no para múltiples usuarios o alojamiento público. Por defecto, la aplicación y el servicio Ghidra se vinculan solo a 127.0.0.1, el modo de depuración está desactivado, los binarios cargados nunca se ejecutan y la clave del proveedor LLM permanece del lado del servidor.
pip install -r requirements.txt -r requirements-dev.txt
python -m pytest
node --test "webui/static/js/tests/**/*.test.mjs"
npm ci && npm run vendor:verify # verifies the vendored Mermaid bundle's integrity
/readyz devuelve 503 — el servicio Ghidra no es accesible en GHIDRA_API_BASE, o API_BASE/MODEL_NAME no están configurados.API_BASE/API_KEY/MODEL_NAME y que el proveedor sea accesible dentro de LLM_TIMEOUT.MAX_UPLOAD_BYTES.ANALYSIS_TIMEOUT del contenedor Ghidra (por ejemplo 5400 para binarios C++/Android con más de 10k funciones) y vuelva a cargar. no está relacionado.| Variable | Por Defecto | Significado |
|---|
API_BASE | requerido | URL base compatible con OpenAI (http/https). Compose falla temprano si no está presente. |
API_KEY | not-used | Clave del proveedor. Nunca se registra ni se envía al navegador; not-used es válida para proveedores locales sin clave. |
MODEL_NAME | requerido | ID del modelo esperado por el endpoint configurado. Compose falla temprano si no está presente. |
LLM_STREAM | auto | Transporte de streaming: auto (stream, retrocede a bloqueante una vez ante un error de compatibilidad previo a la salida), true (siempre stream), false (siempre bloqueante). |
GHIDRA_API_BASE | http://127.0.0.1:9090 | URL base del servicio Ghidra. |
GHIDRA_IMAGE | biniamfd/ghidra-headless-rest:1.2.1@sha256:971591a3... | Versión probada fijada por digest inmutable. :latest también resuelve a este digest; sobrescriba para fijar una versión diferente. |
HOST / PORT | 127.0.0.1 / 5000 | Enlace del servidor de desarrollo. |
MAX_UPLOAD_BYTES | 104857600 | Límite de tamaño de carga. |
CHATS_DIR | webui/chats | Directorio del historial de chats. |
| Workflow | Propósito | Requiere una dirección de función objetivo |
|---|
program_triage | Resumir el propósito probable del programa a partir de metadatos, importaciones, cadenas y funciones. | No |
suspicious_behavior | Primero, indicadores deterministas superficiales; luego, hipótesis acotadas y claramente etiquetadas. | No |
selected_function | Descompilar una función y explicarla con sus llamadores/callees. | Sí |
call_chain | Explorar un vecindario acotado del grafo de llamadas nativo/sintetizado desde una función de inicio. | Sí |
attack_surface_triage | Leer la cobertura/puntuación-K superior determinista, luego inspeccionar en profundidad como máximo tres candidatos; las puntuaciones son prioridades, no veredictos. | No |
vulnerability_hypothesis | Seleccionar un candidato acotado y presentar evidencias, contraevidencias y preguntas abiertas; nunca auto-confirma. | No |
LLM_TIMEOUT