Extracción determinista con PyGhidra, triaje y pipeline local de backend de compilador con LLM para la reimplementación en C.
Gracias por descargar mi pipeline de Ghidra + LLM.
Este es mi primer README. ASL (lengua de signos americana) es mi primera lengua, así que mi inglés no es perfecto. Hice lo que pude.
Me encanta una vieja simulación de PC que he jugado desde la infancia, y quiero mejorarla por dentro.
Mirar juegos de código abierto como OpenRA y OpenTTD me enseñó esto: una reimplementación hecha por un aficionado no consiste en obtener el código fuente original. Consiste en construir una nueva versión de código abierto del juego que pueda cargar los recursos del original. Así cualquiera puede ampliarla o contribuir.
Para hacer el trabajo uso dos tipos de IA juntas:
Cada función recibe una etiqueta. Esto ahorra mucho tiempo, porque no desperdicio esfuerzo en el gran conjunto de basura del SO y del runtime.
|-----------|------------------------------------------------------------------------------------------------------------------
| Etiqueta | Significado |
|---|---|
| KEEP | La lógica propia del juego (por ejemplo el modelo de vuelo, el modelo de daño, TrackIR) |
| WRAP | Pegamento orientado a Java que llama a APIs del SO o de entrada: conserva la firma, escribe un nuevo cuerpo. |
| (IL-2 1946 es un motor interesante: C++ y Java juntos.) | |
| REPLACE | Runtime C antiguo, asignador de memoria, thunks: los proporciona el compilador o el SO, así que una nueva versión de 64 bits no los necesita |
| UNKNOWN | No está claro: revísalo a mano |
| ----------- | ------------------------------------------------------------------------------------------------------------------ |
En mi programa de prueba, alrededor del 44% de las funciones eran REPLACE, así que nunca necesitaron ser convertidas.
Al principio confiaba en que el pseudocódigo C tenía todas las respuestas. Eso fue ingenuo. Es la interpretación que hace Ghidra del ensamblador, y adivina (tipos de variables, argumentos perdidos).
El ensamblador es la verdad cruda. No tiene tipos de variables, pero contiene el comportamiento exacto de cada función. Así que los scripts leen el ensamblador y lo convierten en un plano en forma similar a C. El C de Ghidra se conserva solo como pista.
Mis primeras pruebas usaban los LLM locales (Qwen 2.5 Coder, DeepSeek Coder V2 Lite, Mellum 2) para leer el ensamblador directamente. Nunca funcionó de forma fiable. Alucinaban, porque están hechos para escribir código, no para leer código máquina crudo.
Tras muchos experimentos fallidos dividí el trabajo:
NOTA: Cómo comprueba Python la respuesta
Comprobaciones de texto: el nombre de la función, cada llamada, global y cadena del plano, los bucles, los tamaños de paso, las constantes comparadas, el valor de retorno, y que no queden nombres de registros ni nombres inventados.
comprobación de compilación con gcc: el código se compila con gcc (solo sintaxis, no se ejecuta nada). Esto ayudó mucho. En una ejecución temprana, las comprobaciones de texto dieron por válidas las respuestas de Mellum 2, pero ninguna de ellas compilaba, debido a un comentario de cabecera escrito fuera de un comentario. gcc detecta lo que las comprobaciones de texto no pueden ver: variables no declaradas o redeclaradas, tipos incorrectos y llaves o puntos y coma mal formados. Una función cuenta como PASS solo cuando las comprobaciones de texto y la compilación están ambas correctas. gcc no demuestra que la lógica sea correcta, así que sigo leyendo el código contra el plano.
Si una comprobación falla, el LLM recibe la lista de lo que falló e intenta una vez más.
Python corrige pequeños deslices por sí mismo, sin el LLM: declara cada variable una vez, envuelve las líneas de cabecera sueltas en un comentario, hace que el último return devuelva el resultado correcto, y añade los includes y las declaraciones.
La lista de verificación surgió después de ver a los LLM fallar en funciones muy largas. Funciona como la lista de verificación que usa un piloto antes del despegue y el aterrizaje. Python la escribe a partir de la función y comprueba la respuesta contra ella. En mis pruebas, las funciones largas empezaron a pasar, y las ejecuciones se volvieron más rápidas.
|-------------------|---------------------------------------|---------------------------------------------
| Carpeta | Qué hace | Leer |
|---|---|---|
ghidra_pipeline | Volcado, agrupación, triaje, roles | ghidra_pipeline/INSTRUCTION.txt |
llm_pipeline | Planos y el ejecutor del LLM (v3) | llm_pipeline/INSTRUCTION_BLUEPRINT_LLM.txt |
| ------------------- | --------------------------------------- | --------------------------------------------- |
Empieza con ghidra_pipeline, luego pasa a llm_pipeline cuando estés listo para usar tus LLM locales.
Primero, analiza tu programa en PyGhidra y ejecuta PyGhidra Scripts/decompile_full_dump.py.
Los dos archivos INSTRUCTION explican la configuración de las carpetas. Luego:
Primero, analiza tu programa en PyGhidra y ejecuta PyGhidra Scripts/decompile_full_dump.py.
Los dos archivos INSTRUCTION explican la configuración de las carpetas. Luego:
python .\make_full_lite_v2.py --in . --out .\OUT
python .\triage_evidence_v2.py --lite .\OUT\LITE_AC
python .\build_roles_v2.py --triage .\OUT\TRIAGE
python .\blueprint_v3.py --group ".\SOURCE\LITE_AC\<GroupName>" --out ".\G_<GroupName>\BLUEPRINT_v3"
python .\run_blueprint_llm_v3.py --bp ".\G_<GroupName>\BLUEPRINT_v3" --out ".\G_<GroupName>\RUN1_v3_<model>" --model <model name>
Necesitas Ghidra con PyGhidra, Python 3, LM Studio (un modelo cargado) y gcc (recomendado, usado como verificación de compilación).