2 puntos por GN⁺ 2024-03-18 | 1 comentarios | Compartir por WhatsApp
  • LLM4Decompile es un proyecto open source de modelos de lenguaje grandes que convierte binarios Linux x86_64, en niveles de optimización GCC O0~O3, de vuelta a código fuente C legible por humanos
  • El enfoque consiste en convertir primero el binario a ensamblador con Objdump y luego hacer que el LLM lo descompile a código C; también ofrece la familia LLM4Decompile-Ref, que refina el pseudocódigo generado por Ghidra
  • Los modelos están publicados en tamaños de 1.3B~22B, y llm4decompile-9b-v2 registró una tasa de reejecutabilidad de 64.9% en el benchmark Decompile
  • La métrica de evaluación es la reejecutabilidad, que verifica si el código descompilado pasa pruebas predefinidas y se ejecuta correctamente; se usan como benchmarks 164 funciones C de HumanEval-Decompile y 2,621 funciones de ExeBench
  • En 2025, el proyecto publicó decompile-bench y SK²Decompile, y se está expandiendo con el objetivo de integrar más arquitecturas, configuraciones y herramientas de descompilación

Objetivo y alcance de soporte de LLM4Decompile

  • LLM4Decompile es un proyecto open source de modelos de lenguaje grandes especializado en descompilación
  • La versión actual descompila binarios Linux x86_64 a código fuente C legible por humanos en el rango de niveles de optimización GCC O0~O3
  • El proyecto está trabajando en ampliaciones para soportar una gama más amplia de arquitecturas y configuraciones
  • Hay dos formas principales de uso
    • LLM4Decompile-End: familia de modelos que descompila binarios directamente
    • LLM4Decompile-Ref: familia de modelos que refina con un LLM el pseudocódigo descompilado por Ghidra

Flujo de entrenamiento y evaluación de descompilación

  • El proceso de compilación comienza con código fuente C y genera un ejecutable pasando por preprocesamiento, compilación, ensamblado y enlazado
  • La descompilación sigue este proceso en sentido inverso y convierte el código binario de vuelta en un archivo fuente
  • Como los LLM no pueden procesar datos binarios directamente, primero se debe desensamblar el binario a lenguaje ensamblador con Objdump
  • El README explica que el binario y el ASM desensamblado se tratan como equivalentes porque pueden convertirse entre sí
  • En el entrenamiento se calcula la pérdida entre el código descompilado y el código fuente original, y en la evaluación se comprueba la funcionalidad verificando si pasa las aserciones de prueba

Métrica de evaluación y benchmarks

  • La métrica clave es Re-executability
    • Verifica si el código descompilado se ejecuta correctamente
    • Evalúa si pasa todos los casos de prueba predefinidos
  • HumanEval-Decompile es una colección de 164 funciones C que dependen solo de la biblioteca estándar de C
  • ExeBench es una colección de 2,621 funciones tomadas de proyectos reales
    • Incluye funciones definidas por usuarios, estructuras y macros

Modelos publicados y rendimiento

  • LLM4Decompile incluye modelos de 1.3B~33B parámetros, publicados en Hugging Face
  • Las tasas de reejecutabilidad de los principales modelos son las siguientes
  • La familia V1.5 fue entrenada con un dataset más grande de 15B tokens y una longitud máxima de tokens de 4,096, y afirma haber logrado una mejora de rendimiento de más del 100% frente a modelos anteriores
  • La familia V2 está basada en Ghidra y fue entrenada con 2B tokens para refinar el pseudocódigo de descompilación producido por Ghidra
  • Se afirma que 22B-V2 mostró un rendimiento adicional 40.1% superior al de 6.7B-V1.5

Publicaciones recientes

  • El 4 de octubre de 2025 se publicó SK²Decompile
    • La etapa 1, Structure Recovery, es decir, Skeleton, convierte binarios o pseudocódigo en una representación intermedia ofuscada
    • La etapa 2, Identifier Naming, es decir, Skin, genera código fuente legible por humanos con identificadores significativos
    • Enlaces de modelos: sk2decompile-struct-6.7b, sk2decompile-ident-6.7
  • El 20 de mayo de 2025 se publicó decompile-bench
    • Incluye 2 millones de pares función binaria-fuente para entrenamiento
    • Incluye 70,000 pares de funciones para evaluación
    • Los detalles están en la carpeta decompile-bench
  • El 17 de octubre de 2024 se publicó decompile-ghidra-100k
    • Incluye un total de 100,000 muestras de entrenamiento, 25,000 por cada nivel de optimización
    • Ofrece un script de entrenamiento que se ejecuta en unas 3.5 horas en una sola GPU A100 40G
    • El costo de reproducción rápida es inferior a 20 dólares en total y logra una tasa de reejecutabilidad de 0.26
  • El 23 de septiembre de 2024 se publicó LLM4Decompile-9B-v2
    • Fue ajustado mediante fine-tuning sobre Yi-Coder-9B
    • Logró una tasa de reejecutabilidad de 0.6494 en el benchmark Decompile

Flujo de uso

  • El inicio rápido consiste en clonar el repositorio, crear un entorno Conda e instalar requirements.txt
  • La etapa de preprocesamiento compila código C a binario con GCC y luego extrae instrucciones de ensamblador con objdump -d
  • El nombre de la función debe cambiarse por el de la función que se quiere descompilar, en lugar de func0 del ejemplo
  • Se espera que el ensamblador de entrada tenga la siguiente forma
    • <FUNCTION_NAME>:
    • Varias líneas posteriores de instrucciones de ensamblador
  • La etapa de descompilación carga un modelo de Hugging Face con AutoTokenizer y AutoModelForCausalLM de transformers, y genera código C a partir del prompt de ensamblador
  • También es posible usar Docker
    • Después de construir la imagen, se ejecuta el contenedor con opciones de GPU
    • Se ofrece un flujo para ejecutar demo.py en el directorio ghidra

Formato de datos de HumanEval-Decompile

  • Los datos de HumanEval-Decompile se almacenan como una lista JSON en llm4decompile/decompile-eval/decompile-eval-executable-gcc-obj.json
  • El número de muestras es 164*4, resultado de multiplicar 164 funciones por los niveles de optimización O0, O1, O2 y O3
  • Cada muestra tiene 5 claves
    • task_id: ID del problema
    • type: etapa de optimización, una de O0, O1, O2 u O3
    • c_func: solución en C del problema de HumanEval
    • c_test: aserciones de prueba en C
    • input_asm_prompt: instrucciones de ensamblador y prompt
  • El script de evaluación está en la carpeta evaluation

Elementos en curso y licencia

  • Los elementos en curso incluyen un dataset de entrenamiento más grande y un proceso de limpieza, soporte para lenguajes, plataformas y configuraciones populares, soporte para ejecutables e integración con herramientas de descompilación como Ghidra y Rizin
  • El dataset de entrenamiento más grande y el soporte para ejecutables figuran como elementos completados el 13 de mayo de 2024
  • El repositorio de código está licenciado bajo MIT License y DeepSeek License
  • El paper está en arXiv:2403.05286, y el proyecto también ofrece materiales de Colab y YouTube

1 comentarios

 
GN⁺ 2024-03-18
Comentarios de Hacker News
  • Es una idea interesante, pero me pregunto qué tan confiables serán los resultados
    Al recompilar, podría salir un código máquina distinto, así que sería difícil identificar alucinaciones, y preocupa que falle silenciosamente, sobre todo en estructuras nuevas que podrían ser clave en el código
    Me pregunto si, al ejecutarlo de forma generativa, hay alguna manera de que el LLM reporte también su nivel de confianza en ciertos fragmentos, aunque al final parece que hará falta verificación humana

    • Por eso es importante la conversión de ida y vuelta
      Si decompilas un binario a código fuente y luego lo vuelves a compilar a binario, debería salir el binario original, y bastaría con iterar hasta que la pérdida baje a un nivel aceptable
      El aprendizaje por refuerzo encaja muy bien en problemas así, y de hecho se sabe que es anormalmente efectivo en este tipo de casos
    • Los LLM son esencialmente probabilísticos, así que funcionan bastante bien en áreas no exactas como el procesamiento de lenguaje natural, pero usarlos para decompilación o desensamblado me parece, personalmente, un caso de “elegir mal la herramienta”
      Puede ser un experimento para explorar el meme tan común hoy de “simplemente usemos un LLM”, pero el contraargumento más fuerte es que los decompiladores existentes ya lo hacen mejor con mucho menos cómputo
    • Se podría usar una herramienta de verificación formal que reciba la entrada, la salida y una prueba formal de que la salida coincide semánticamente con la entrada, y hacer que el LLM genere también esa prueba junto con la salida
      Después, una herramienta de verificación podría comprobar si el resultado es correcto según la prueba proporcionada por el LLM
      Claro, construir y entrenar un LLM capaz de producir esas pruebas sería un reto aún mayor, pero podría ser una forma segura de detectar alucinaciones
    • También se puede usar fuzzing diferencial
    • Aunque no sea completamente confiable, al modificar binarios normalmente basta con cambiar solo algunas funciones
      Así que solo habría que recompilar esas pocas funciones
  • Si conoces a los desarrolladores que hicieron una aplicación, sería interesante ver si se puede entrenar un módulo de decompilación usando su código pasado como datos de entrenamiento
    Por ejemplo, Super Mario 64 y Zelda 64 ya fueron completamente decompilados, y otros juegos de N64 siguen en proceso, así que me pregunto si se podría mapear a los desarrolladores que participaron en esos dos juegos, estimar incluso quién hizo qué módulo, y usar eso para decompilar otros juegos
    Si esto llegara a mejorar mucho, uno podría soñar con descifrar todos los binary blobs dentro de una PC, abrir los drivers e incluso destapar el OS completo
    Incluso se puede imaginar revivir Windows XP en vez de conformarse con Linux, backportearle seguridad moderna y compatibilidad con apps, y dejarle a Microsoft su Windows 11

    • Los decompiladores ya existen y funcionan bien
      Si un LLM puede hacer lo mismo que un decompilador existente, es muy probable que los abogados lo consideren un procedimiento equivalente
      El problema principal no es técnico, sino legal y político
    • Traté un tema parecido en mi tesis de licenciatura, y había investigaciones que mostraban que, bajo ciertas condiciones, se puede entrenar un clasificador de identificación de autor capaz de adivinar quién escribió un programa viendo solo el binario compilado
      No sé si eso se haya usado mucho en la práctica, pero es genial que el estilo personal de programación permanezca incluso después del proceso de compilación, hasta el punto de poder distinguir entre programas compilados de distintas personas
    • No creo que se pueda identificar el código realmente escrito en sí
      El resultado sería muy parecido al original, pero muchos elementos de estilo de código desaparecen, y el estilo que parezca quedar probablemente sería más bien una alucinación
  • Es fácil crear un gran dataset de pares de entrada/salida con código C público, así que este es un caso de uso muy bueno para el fine-tuning de LLM

    • También parece bastante ventajoso en este caso generar muchísimo código C con un LLM de código, por ejemplo un modelo como DeepSeek, verificar si compila y usarlo como datos sintéticos de entrenamiento
      Normalmente la gran preocupación con los datos sintéticos de entrenamiento es su calidad, pero aquí lo clave es que el código compile
  • Si leí bien la métrica de rejecutabilidad en la imagen de resultados, la idea es excelente, pero en la práctica no parece funcionar muy bien
    https://raw.githubusercontent.com/albertan017/LLM4Decompile/...
    Como complemento, la rejecutabilidad es una métrica clave para medir la precisión semántica
    Se recompila el resultado de la decompilación y se ejecutan casos de prueba para evaluar si la lógica y el comportamiento del programa se conservaron; la recompilabilidad y la rejecutabilidad representan, respectivamente, la restauración sintáctica y la preservación semántica

  • Este problema es interesante al menos en dos sentidos
    Primero, un decompilador ideal podría debilitar el valor del código fuente propietario
    Segundo, como hay abundante código C público, es fácil construir datasets emparejados de ensamblador y código fuente, con variedad en niveles de optimización, compiladores y plataformas
    Aun así, me pregunto por qué los autores hicieron fine-tuning sobre DeepSeek-Coder
    También me pregunto si sería posible entrenar un LLM desde cero con un dataset parecido, qué tamaño haría falta y si se podría ejecutar localmente

    • La mayor parte del código propietario corre detrás de firewalls, así que un enfoque así probablemente no tendría mucho impacto sobre él
      Aunque la tarea deseada no esté tan cerca del modelo inicial, casi siempre es mejor partir de un modelo preentrenado que de una inicialización aleatoria
    • Un decompilador ideal no existe
      El compilador pierde información, así que en cierto sentido nunca puede existir, e incluso si se toma una visión generosa como “comprensión de alto nivel del código resultante”, esto es un problema del nivel de AGI dentro del campo de la seguridad informática
      Nadie se ha acercado todavía a eso
    • Entrenar un modelo de lenguaje desde cero requiere muchos datos
      Llama2 se desarrolló con 2 billones de tokens, mientras que este dataset está en alrededor de 4 mil millones de tokens
      Tampoco es fácil decidir simplemente el tamaño adecuado del modelo, y en los experimentos un modelo de 7 mil millones de parámetros mostró 21% de ejecutabilidad, mientras que uno de 1 mil millones se quedó en 10%
      Aun así, la recompilabilidad de ambos es bastante similar
      El modelo de 1 mil millones de parámetros requiere al menos 2 GB de memoria GPU, así que puede correr en la mayoría de las GPU, y el de 7 mil millones necesita 14 GB, por lo que encaja bien en la línea 3090/4090
      El modelo de 33 mil millones, en una sola tarjeta, deja como opción una A100 de 80 GB, y técnicamente también podría usarse en una MacBook, aunque en la práctica nadie querría hacerlo
    • Probablemente se deba a la diferencia entre el costo de entrenamiento y el costo de fine-tuning
      También podría ser simplemente un punto de partida para validar la idea
  • Están creando un decompilador inverso basado en LLM para bytecode de Python https://github.com/kukas/deepcompyle
    No parece haber mucha gente trabajando en esta línea de investigación, pero ahora que ya es posible tener contextos de atención largos, me parece que podría ser bastante interesante
    Si alguien conoce a un equipo que trabaje en este tema, hay interés en colaborar

    • Me pregunto si realmente hay ventajas en usar LLM para bytecode de Python
      Por experiencia, el bytecode de Python es lo bastante de alto nivel como para convertirlo directamente a código fuente
    • Me pregunto por qué Python
      Python tiene un gran ecosistema de bibliotecas open source, pero no diría que se use mucho para software distribuido en forma binaria
    • Existe PyLingual, pero lamentablemente no es open source
      Tampoco está claro si está basado en LLM
    • Parece que la mayor parte del trabajo de decompilación inversa está del lado de C
      No da la impresión de que haya muchos proyectos de Python que se compilen y distribuyan como binarios
  • Tenía planes de intentar algo así
    En algún momento alguien logrará romper la barrera de una canalización de entrada binaria → salida de buen código fuente, pero parece que aún faltan algunos años
    Lo digo porque no parece que haya muchísimo dinero al final de este problema, aunque podría estar equivocado
    Un buen enfoque intermedio sería construir una canalización de decompilación ejecutando Ghidra en modo headless y combinar la estricta exactitud sintáctica del decompilador con la capacidad intuitiva de los LLM
    Como en AlphaGeometry, el decompilador y el LLM deberían compensar las debilidades del otro: https://deepmind.google/discover/blog/alphageometry-an-olymp...
    También haría falta algo como AICI como pegamento para orquestar la generación de código fuente en C: https://github.com/microsoft/aici
    En vez de usar los pesos del LLM para generar código fuente en C gramaticalmente correcto, sería preferible hacer que piense en nombres de variables, patrones de snippets y elecciones de arquitectura, y dejar que herramientas como Ghidra o LLVM se encarguen del resto
    Es un comentario algo especulativo de un exestudiante de posgrado hablando desde el sillón, pero es admirable que estos investigadores se hayan lanzado a esto, y el hecho de que los autores mencionen una integración con Ghidra en trabajos futuros sugiere que van en la dirección correcta

  • Es interesante que el modelo de 6 mil millones lo haga mejor que el de 33 mil millones
    Me pregunto si eso significa que el modelo de 33 mil millones necesita más datos de entrenamiento
    Si comparas uno preentrenado con cerca de 1 millón de programas en C con DeepSeek-Coder, entrenado con del orden de billones de tokens, la diferencia en volumen de datos es de varios órdenes de magnitud
    También me pregunto cómo se compara con soluciones que no usan LLM

    • Esta tendencia ya lleva un tiempo viéndose en los LLM
      La mayoría de los LLM están bastante subentrenados, y los modelos de 7 mil millones son de los menos subentrenados entre los modelos generalistas, por eso se difundieron mucho en la comunidad de fine-tuning de LLM
    • No es fácil entrenar un modelo de 33 mil millones
      En el fine-tuning ingenuo, donde simplemente se ajusta el modelo siguiendo el enfoque estándar, entrenar modelos grandes es complicado, y no solo influye la cantidad de datos, sino también su depuración, la tasa de aprendizaje, el decaimiento y prácticamente todos los demás factores en el rendimiento final
    • No estoy seguro de que se puedan comparar tan directamente alrededor de 1 millón de programas en C con 2 billones de tokens
      Para hacerlo habría que asumir que el tamaño promedio de esos programas en C es varios órdenes de magnitud menor que 2 millones de tokens; quizá sea cierto en la práctica, pero suena como una suposición bastante optimista
  • Me pregunto si, si esto funciona, significaría replicar 1:1 el código máquina del compilador
    Si es así, implicaría que el código completo podría existir como una distribución de probabilidad dentro del espacio latente
    O, más probablemente, podría tratarse de replicar solo la lógica y luego traducirla al lenguaje objetivo
    Los binarios cuya compilación requiera entradas no deterministas, como claves o hashes, parecen propensos a romperse
    Es realmente fascinante

  • Sorprende que GPT-4 todavía se desempeñe bastante bien en la comparación
    Este modelo genera mucho mejor código que compila, pero tiene menor precisión al reproducir código cuyo comportamiento sea correcto
    Aun así, es bastante impresionante

    • Es muy impresionante que GPT-4 lo haga tan bien pese a no ser un modelo entrenado directamente para decompilación inversa
      Estamos mejorando el modelo, así que sigan atentos a las actualizaciones
    • Sería impresionante si este enfoque funcionara tan bien para C++ como para C, pero aquí no es el caso