3 puntos por GN⁺ 2024-03-31 | 1 comentarios | Compartir por WhatsApp
  • rev.ng publicó el backend del decompilador revng-c, convirtiendo en código abierto su motor de decompilación, y al mismo tiempo lanzó una beta cerrada de la UI, un nuevo sitio web, rev.ng Hub y documentación
  • En local, se puede configurar el CLI con el script de instalación y luego usar revng artifact y revng ptml para ver resultados de decompilación en forma de código C válido
  • La UI interactiva está basada en VSCode, apunta a funcionar tanto en el navegador como en una app independiente, y se ofrece en una beta cerrada con invitaciones FIFO para suscriptores del newsletter
  • La recuperación automática de estructuras de datos, el reversing colaborativo, el soporte para varias arquitecturas y la extensibilidad son objetivos clave, pero el QA actual está más enfocado en binarios Linux x86-64
  • El framework y el CLI son de código abierto, la UI en la nube es gratis para proyectos públicos, y los proyectos privados y la UI independiente offline se ofrecen bajo un modelo de pago

Transición a código abierto y beta cerrada

  • rev.ng liberó como código abierto revng-c, el backend de su decompilador
    • Con esto, todo el motor de decompilación pasa a ser de código abierto
    • También se ofrece documentación inicial en docs
  • La UI empezará a enviar invitaciones a beta cerrada para suscriptores del newsletter
    • Las invitaciones se enviarán en orden FIFO
    • Para participar en la beta, hay que registrarse en el newsletter
  • También se presentaron el nuevo sitio web y rev.ng Hub
    • rev.ng Hub es el punto de entrada a la versión en la nube
    • Los usuarios beta pueden crear proyectos, ejecutar la UI en el navegador y colaborar con otros usuarios
    • Incluso quienes no estén en la beta cerrada pueden explorar proyectos públicos
  • También ofrecen demos privadas para quienes quieran ver rev.ng en acción directamente

Probar rev.ng desde el CLI

  • revng puede instalarse en un solo directorio sin privilegios de root, y se elimina simplemente borrando ese directorio
curl -L -s https://rev.ng/downloads/revng-distributable/master/install.sh | bash
cd revng
source ./environment
  • El ejemplo example.c es un programa simple que devuelve argc * 3
int main(int argc, char *argv[]) {
  return argc * 3;
}
  • Después de compilar con gcc, al ejecutar revng artifact se puede obtener un resultado de decompilación en forma de archivo único
gcc example.c -o example -O2
revng artifact \
        --analyze \
        --progress \
        decompile-to-single-file \
        example \
        | revng ptml --color \
        | grep -A2 -B1 '[^_]main\b' \
        > decompiled.c

Alcance de la beta y objetivos de prueba

  • Para usar la UI hay que registrarse en el newsletter, y las invitaciones se enviarán en lotes pequeños
  • Este lanzamiento se enfoca en mostrar la UI y los resultados de decompilación con algunos binarios, además de recibir feedback y reportes de bugs sobre trabajo con binarios reales
  • Los binarios no triviales usados en las pruebas y su tamaño de .text son los siguientes
  • rev.ng soporta varios ABI y plataformas, pero el QA inicial en esta etapa está concentrado en binarios Linux x86-64
  • Si surge algún problema, se puede pedir ayuda en Discourse

La experiencia de decompilación que busca rev.ng

  • Los principales enfoques de rev.ng son la recuperación automática de estructuras de datos, una UX moderna, reversing colaborativo, amplio soporte de plataformas y extensibilidad
  • Recuperación automática de estructuras de datos

    • Con Data Layout Analysis se puede reconstruir automáticamente el layout de struct mediante análisis interprocedimental
    • El ejemplo de nodo de lista enlazada usa una estructura con un arreglo int64_t data[5] y un puntero al siguiente nodo
    • La salida de rev.ng genera automáticamente una estructura y código de función detectando tanto el tamaño 5 del arreglo como el acceso al puntero del siguiente elemento
    • La salida del decompilador es código C sintácticamente válido
    • Esta función ya está disponible
  • UI interactiva basada en VSCode

    • La UI está basada en VSCode, así que a quienes usan VSCode les resultará familiar
    • Puede ejecutarse tanto en una pestaña del navegador como en una aplicación independiente
    • Los atajos principales son:
      • Ctrl + Click: ir a la definición de la función o tipo bajo el cursor
      • N: cambiar nombre
      • Y: editar tipo
      • X: mostrar referencias
    • rev.ng es un decompilador interactivo que, cuando hay cambios, vuelve a calcular solo las partes afectadas
    • Actualmente la UI se ofrece a participantes de la beta cerrada
  • Reversing colaborativo

    • La UI de rev.ng usa una arquitectura cliente-servidor
    • Varios usuarios pueden conectarse a la misma instancia del daemon y trabajar al mismo tiempo en el mismo proyecto
    • En la versión en la nube se puede usar rev.ng Hub, una aplicación similar a GitHub para gestionar proyectos
    • La función colaborativa ya funciona, pero todavía necesita mejoras en la experiencia de usuario, y su avance se sigue en roadmap item #797

Cómo manejan el soporte de arquitecturas y plataformas

  • rev.ng usa la parte inicial del pipeline de QEMU para levantar código ejecutable a tiny code, luego convertirlo a LLVM IR y después decompilarlo
  • Gracias a esta estructura, puede dar soporte con relativa facilidad a las arquitecturas que soporta QEMU
  • Además del soporte de arquitecturas, también es importante el soporte de plataformas, especialmente ABI
    • rev.ng usa un formato de descripción ABI para describir atributos ABI de manera declarativa
    • Ese formato fue diseñado de forma suficientemente general como para facilitar el soporte de nuevos ABI
  • El estado actual del soporte es el siguiente
    • Arquitecturas: x86, x86-64, ARM, AArch64, MIPS y s390x con distintos niveles de madurez
    • Formatos binarios: soporte para ELF, PE/COFF y Mach-O
    • Importación: soporte para .idb, información de depuración DWARF e información de depuración PDB
  • La mayor parte del QA se hizo sobre binarios Linux x86-64; el resto aún requiere QA adicional
  • Más QA para otras plataformas se sigue en roadmap item #58

Extensibilidad y scripting

  • rev.ng apunta a ser un framework para herramientas de ingeniería inversa, y salvo la UI interactiva, todo el proyecto es de código abierto
  • El archivo de proyecto model es un documento YAML, así que si se puede parsear JSON o YAML, se puede hacer scripting con rev.ng
  • El modelo incluye la arquitectura del binario objetivo de decompilación, el ABI predeterminado, segmentos, lista de funciones, lista de tipos y más
  • Se puede modificar el modelo con wrappers para Python y TypeScript
    • Ya existen wrappers para manipular el modelo, pero todavía no hay una forma sencilla de ejecutar análisis y traer artifacts
    • Un cliente completo para Python se sigue en roadmap item #17
  • En la representación interna se usa mucho LLVM IR, por lo que se puede aprovechar el ecosistema de herramientas de LLVM

Diferencia entre el CLI open source y la UI de pago

  • El framework de rev.ng es completamente de código abierto, y desde el CLI se puede decompilar cualquier objetivo deseado
  • La oferta de la UI se divide en tres modalidades
    • La UI en la nube para proyectos públicos puede usarse gratis
    • La UI en la nube para proyectos privados requiere suscripción
    • La UI completamente independiente y totalmente offline se ofrece como producto de pago
  • El uso en la nube funciona así
    • Se crea un proyecto en rev.ng Hub y se invita a colaboradores
    • La UI se ejecuta en el navegador
    • El backend corre en la nube de rev.ng
  • Si no hay problema en hacer público el archivo del proyecto, se puede usar gratis la versión en la nube de rev.ng con UI incluida
  • También se puede conversar sobre una instalación de servicio de nube privada on-premise con Kubernetes

Roadmap hacia 1.0 y canales de contacto

  • El roadmap hacia 1.0 está dividido en 4 niveles
    • Tier 1: versión alfa, demos para conocidos, completado
    • Tier 2: versión beta, acceso a la versión en la nube para suscriptores del newsletter, acaba de comenzar
    • Tier 3: beta abierta, próximamente
    • Tier 4: lanzamiento 1.0, próximamente
  • El progreso detallado puede consultarse en la página del roadmap
  • Las novedades del proyecto y los canales de soporte son los siguientes
    • X/Twitter: novedades de desarrollo y anuncios importantes
    • Discord: conversación en tiempo real con el equipo de desarrollo
    • Discourse: soporte para usuarios y reportes de bugs
    • GitHub: desarrollo open source y registro de issues
    • Monthly newsletter: participación en la beta cerrada y novedades mensuales
    • E-mail: consultas privadas

1 comentarios

 
GN⁺ 2024-03-31
Opiniones de Hacker News
  • El modelo de precios es que el framework rev.ng es completamente open source y, desde la CLI, se puede decompilar cualquier cosa.
    La UI será gratis en la nube para proyectos públicos; para proyectos privados habrá una suscripción en la nube, y una app offline totalmente independiente se ofrecerá como producto de pago.
    En comparación, Hopper cuesta 100 dólares con 1 año de actualizaciones incluido https://www.hopperapp.com/index.html, Ghidra y Radare2 son software libre y open source, así que son completamente gratis, e IDA Pro es muy caro.

    • Binary Ninja también es una buena opción.
      Por lo que he usado, se parece bastante a IDA, pero es más amigable y tiene muchas funciones bien diseñadas que aumentan la productividad.
      No he usado Hopper, pero con Ghidra y Radare2 mi experiencia de desarrollo no fue muy buena, y el código C generado tampoco era fácil de leer. Eso sí, hablo de cuando los usé hace varios años.
      Binja cuesta 300 dólares; la versión comercial cuesta 1500 dólares y también hay descuento para estudiantes: https://binary.ninja/features
    • La decompilación suele ser una de las partes menos importantes y menos confiables de IDA/Ghidra, así que compararlos solo por eso es injusto.
      Aun así, siempre hacen falta buenos decompiladores de C, así que cualquier nuevo intento es bienvenido.
    • Me gusta mucho el modelo de licencia de pago único y período definido de actualizaciones.
      Aunque me da curiosidad cómo lo hacen cumplir sin que la app requiera conexión a internet.
  • Al ver la página del equipo https://rev.ng/about y las contribuciones de código https://github.com/revng/revng/graphs/contributors, se ve un poco inusual que el CEO (aleclearmind) tenga muchos más commits que el CTO (pfez).
    Otros CEO suelen decir que casi no tienen tiempo para programar, y los CTO normalmente también se enfocan más en gestión y menos en programación real.
    Aun así, si esta forma de trabajar les funciona, para el equipo debe ser bastante interesante. Edición: no revisé la línea de tiempo.

    • El CTO trabaja principalmente en el backend de decompilación revng-c, que acaban de publicar: https://github.com/revng/revng-c/commits/develop/
      Al final planean fusionar los dos repositorios.
      Y yo desarrollo todos los días, pero por alguna razón GitHub no está asociando correctamente mi usuario.
      De hecho, sí es divertido.
    • El CTO ha hecho más commits recientes, y los commits de aleclearmind cayeron a 0 después de 2020, así que parece que a él también se le volvió difícil sacar tiempo para programar.
    • No estaba intentando criticar en absoluto, así que me da un poco de curiosidad por qué recibí votos negativos.
      De hecho, me gustó ver eso, y me pareció interesante porque era distinto de lo que había visto en otros lugares.
      ¿Me votaron negativo porque no era interesante o no era inusual?
  • Parece una gran empresa impulsada por uno de los mejores libros de teoría de lenguajes de programación que existen: https://link.springer.com/book/10.1007/978-3-662-03811-6
    “También conoció a Pietro, quien se convertiría en su cómplice. De forma bastante romántica, lo conoció gracias al libro que terminaría siendo la base de la empresa.”
    https://rev.ng/about

    • La historia completa detrás de ese libro es esta. Empecé a estudiar compiladores, pero la teoría me resultaba demasiado difícil, y los libros famosos no me servían, así que estaba bastante desanimado.
      Entonces encontré este libro, que parecía denso pero claro, y le pregunté a mi director si podía comprarlo; me dijo: “primero revisa la biblioteca de la universidad”.
      La biblioteca tenía una copia, pero ya estaba prestada, y como yo estaba en el único grupo que investigaba compiladores pensé: “¿quién se atreve a hacer compiladores fuera de nuestro grupo?”.
      Fui a la biblioteca a preguntar quién lo había tomado prestado, pero me dijeron que no podían decírmelo por privacidad; solo pregunté por la tercera letra del apellido y la segunda letra del nombre, y conseguí una Z y una I.
      Lo encontré aquí: https://www.deib.polimi.it/ita/personale-lista-alfabetica
      Con el tiempo nos hicimos amigos y empezamos una empresa juntos.
      Hizo falta muchísimo trabajo para llegar al lanzamiento.
  • Sería bueno que asignara automáticamente nombres de variables y de miembros de structs según cómo el código maneja las variables y los miembros de las estructuras.
    Por ejemplo, el puntero al siguiente nodo en una lista enlazada debería ser fácil de identificar como next.
    Parece posible descargar todo GitHub, buscar variables cuyo layout e interacciones en el código sean lo más similares posible y, si la confianza es suficientemente alta, usar ese nombre.

    • Antes intenté hacer algo así manualmente.
      Por ejemplo, si detectaba una variable de inducción, le cambiaba el nombre a i.
      Pero ahora parece bastante claro que la forma correcta de hacer esto es usar LLM.
      Dicho eso, en esta etapa somos más bien quienes construyen una base sólida; una vez que la base esté lista, renombrar o agregar comentarios con modelos ya existentes será relativamente fácil.
      La clave es que nosotros hagamos el trabajo difícil de decompilación que necesita 100% de precisión, y que se puedan introducir LLM en partes donde se aceptan aproximaciones, como nombres y comentarios.
      En cualquier caso, escribir scripts para renombrar es bastante fácil, así que revisen la documentación: https://docs.rev.ng/user-manual/model-tutorial/
    • Eso suena realmente genial, algo como http://jsnice.org/.
      Un paper que explica qué hace JSNice internamente: https://files.sri.inf.ethz.ch/website/papers/jsnice15.pdf
    • Suena parecido a sidekick de Binary Ninja.
    • ¿Algo como GitHub Copilot para reversing?
  • No funciona con mi archivo ELF
    Al ejecutar ./revng artifact --analyze --progress decompile-to-single-file ../maytag.ko, aparece Only ELF executables and ELF dynamic libraries are supported, y el archivo figura como ELF 64-bit LSB relocatable, x86-64, version 1 (FreeBSD), not stripped
    ¿Será que no admite binarios de FreeBSD?
    Corrección: se me pasó que no admite módulos del kernel, y parece que no es tanto por FreeBSD, sino porque simplemente no es un ejecutable

    • ¿Podrías abrir un issue en GitHub y adjuntar el binario?
      Cargar eso no parece tan difícil
  • Me gustaría que se le preste mucha atención al flujo de trabajo colaborativo
    No he usado cosas como IDA Teams, pero sería genial si se pudiera tener una experiencia de ingeniería inversa sin fricción, como Google Docs

    • Ese es nuestro objetivo
      Antes usábamos QtCreator para la UI, pero fue una elección terrible
      Luego cambiamos a VSCode, y justo también podía ejecutarse en el navegador
      Así que le sumamos un poco de Kubernetes y creamos un descompilador en la nube con exactamente la misma experiencia de usuario que la versión completamente independiente
      La parte colaborativa todavía necesita más QA, pero básicamente funciona
      Es una estructura muy simple: un demonio con varios clientes
      Creo que nos inspiramos en una experiencia anterior en CTF, donde “colaborábamos” sobre la sesión X de un servidor con varias ventanas de IDA y varios cursores. Era una forma muy maldita, pero funcionaba
  • ¿Tienen planes de admitir inferencia de tipos?
    Por ahora parece que todas las variables se ven como generic64_t; estaría bueno que detecte tipos automáticamente como Ghidra. Claro que Ghidra también se equivoca a veces

  • Se ve interesante
    Me gustaría probar la versión completamente independiente
    ¿Hay alguna novedad sobre el precio aproximado? Ojalá sea algo accesible para usuarios aficionados

  • Siempre es bueno que haya más herramientas para hacking de binarios
    Como quizá alguien quiera probarlo directamente, dejo sugerencias excesivamente detalladas sobre el formato de empaquetado elegido
    source ./environment es una mala señal. Al bajar el tar, efectivamente configuraba varias variables de entorno, incluyendo PATH, y por suerte no LD_LIBRARY_PATH
    La mayoría tiene el prefijo HARD_, que probablemente sea único, pero REVNG se vería más claro, y chocar con variables de entorno existentes es malo
    También configura AWS_EC2_METADATA_DISABLED="true"; yo no uso AWS, así que no se rompe nada, pero en general se ve sospechoso
    RPATH_PLACEHOLDER, HARD_FLAGS_CXX_CLANG, un PATH largo, cadenas como mingw32/gentoo/mips, etc., se ven frágiles
    Si las instrucciones de ejecución dicen “ahora cambia las variables de entorno”, normalmente me rindo; eso está fuertemente correlacionado con programas que no funcionan bien en sistemas que no son Ubuntu
    Atar el flujo de control de la aplicación al entorno de ejecución tiene más modos de falla de los que parece al principio, y se parece mucho a usar variables globales
    Clang puede incorporar valores predeterminados en tiempo de compilación, como -DCLANG_DEFAULT_CXX_STDLIB=libc++, y DEFAULT_SYSROOT también es útil
    Incluso usando rpath, si el usuario ejecuta con LD_LIBRARY_PATH configurado, eso puede sobrescribir el DT_RUNPATH del binario
    Hoy en día -Wl,rpath en realidad significa runpath, no rpath, y es menos útil; probablemente la invocación deseada sea -Wl,rpath -Wl,--disable-new-dtags, para que el cargador ignore LD_LIBRARY_PATH al buscar bibliotecas
    Con una combinación de flags de compilación de Clang, enlace estático e incrustar binarios dentro del binario, es muy probable que se pueda eliminar por completo la manipulación de variables de entorno
    Que el binario clang-16 esté enlazado dinámicamente y en tiempo de ejecución busque cosas como libLLVMAArch64CodeGen.so.16 también aumenta los modos de falla
    Con LLVM_BUILD_STATIC=ON se puede reducir el problema de que, en un entorno con toolchains de módulos HPC activados, tome bibliotecas equivocadas
    Las herramientas están enlazadas contra libc++.so, libc++abi.so, etc.; valdría la pena considerar libc++ estática y, como mínimo, conviene enlazar libc++abi y libunwind estáticamente dentro de libc++
    Se me agotó por completo la paciencia para distribuir programas enlazados dinámicamente en Linux
    Si el source ourhack del README o variables de entorno dejadas por un sistema de módulos cambian las bibliotecas en tiempo de ejecución de mi aplicación, la experiencia de usuario y el costo posterior de los reportes de bugs se vuelven horribles
    En comparación, el enlace estático es realmente bueno

    • La mayoría de las preocupaciones sobre tocar el entorno solo aplican si realmente se asume que se hace source environment
      De hecho, la razón por la que lo sugerimos es únicamente para usar el GCC que distribuimos para los binarios de demo; la forma de uso prevista es el script ./revng
      En ese caso, los cambios de entorno solo afectan la invocación de revng
      La documentación está aquí: https://docs.rev.ng/user-manual/working-environment/
      Sería bueno agregar una advertencia sobre source ./environment
      Dedicamos mucho tiempo a evitar usar LD_LIBRARY_PATH, y construimos un conjunto de binarios totalmente autocontenidos donde cada ELF referencia sus dependencias con rutas relativas. LD_LIBRARY_PATH es maldad
      Las variables HARD_ solo se usan en el wrapper del compilador y creo que en la práctica casi no hay posibilidad de conflicto
      La discusión original sobre AWS_EC2_METADATA_DISABLED="true" está en https://github.com/revng/revng/pull/309#discussion_r12805759...
      También podríamos evitarlo parcheando el SDK de AWS, pero en cualquier caso solo tiene efecto cuando rev.ng se ejecuta en la nube
      RPATH_PLACEHOLDER y HARD_FLAGS_CXX_CLANG se usan cuando revng enlaza binarios traducidos, y si no te interesa la traducción binaria de extremo a extremo, no son importantes
      Queremos intencionalmente DT_RUNPATH. DT_RPATH está deprecado, y puede haber casos de uso en los que se necesite reemplazar nuestras bibliotecas con LD_LIBRARY_PATH
      Creo que la crítica sobre la “manipulación del entorno” solo es válida cuando no se trata de variables de entorno privadas
      RPATH_PLACEHOLDER, HARD_* y REVNG_* son variables privadas y todas tienen como objetivo la traducción binaria
      Podríamos moverlas a un wrapper de compilador con un alcance más reducido, pero como distribuimos Python junto con esto, no podemos eliminar el entorno por completo
      No alcanza con incorporar algunos flags en Clang. Esos flags también afectan al enlazador, y hay funciones del wrapper que simplemente no se pueden integrar así
      Aun así, sí podríamos moverlas a un lugar más privado
      Parece que desconfías del enlace dinámico, pero nosotros le dedicamos esfuerzo y ahora funciona bastante bien, encontrando siempre la ubicación correcta
      No hardcodeamos rutas absolutas ni hay un paso de instalación que “parchee” los binarios. El directorio descomprimido se puede mover a cualquier lugar
      La solución que usamos no utiliza LD_LIBRARY_PATH, y todos los binarios se referencian entre sí de forma robusta mediante $ORIGIN
      Si ejecutas ./root/bin/python ./root/bin/revng artifact --help, verás que funciona
      De nuevo, source environment es casi solo para demos; en el uso real basta con ejecutar ./revng y el entorno queda intacto
      También distribuimos Python, pero no es obligatorio usarlo. Puedes usar ./revng o interactuar por red en modo daemon
      El enfoque es parsear y modificar el archivo de proyecto YAML con la herramienta de scripting que prefieras y luego invocar ./revng artifact, o interactuar con el daemon: https://docs.rev.ng/user-manual/model-tutorial/
      En consecuencia, nosotros usamos una versión reciente de Python y el usuario puede usar el lenguaje que prefiera

Más adelante planeamos ofrecer en PyPI un wrapper auxiliar compatible con varias versiones de Python
En resumen, no hagan source ./environment; usen ./revng
Me alegra que haya gente que se preocupe por este tipo de cosas
En la próxima gran iteración, quizá podamos simplificar muchas cosas introduciendo nix + mount namespace, lo que permitiría usar /nix/store sin permisos de root
Tal vez sea mejor hablar de este tipo de discusiones en el servidor de Discord que aquí

  • Felicitaciones
    ¿Te arrepientes de haberle encargado el lifting a QEMU TCG, o funcionó bien?
    • Funcionó muy bien. Los arrepentimientos son dos
      Primero, no hicimos rebase de nuestro fork de QEMU durante varios años, y eso nos dejó en una mala situación
      Aun así, justo hoy un miembro del equipo logró hacer lifting con la versión más reciente de QEMU, y también pudimos hacer lifting del código de Qualcomm Hexagon para el que ayudamos a agregar soporte en QEMU
      Al final, seremos el primer decompilador de Hexagon realmente bueno
      Segundo, al centrarnos demasiado en QEMU, el front-end quedó fuertemente acoplado a QEMU
      Ahora hará falta algo de esfuerzo para soportar front-ends adicionales que no estén basados en QEMU, pero no es imposible
      La idea es que, cuando un usuario agregue soporte para una nueva arquitectura, solo tenga que definir en C la estructura de estado de la CPU y algunas funciones que operen sobre ella
      No necesita aprender la representación interna
      En resumen, QEMU fue una excelente elección, y funcionó tan bien que dejamos de tocar esa parte del codebase durante mucho tiempo, lo que generó deuda técnica, pero ya la estamos resolviendo