- 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
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.
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
Aun así, siempre hacen falta buenos decompiladores de C, así que cualquier nuevo intento es bienvenido.
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.
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.
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
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.
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/
Un paper que explica qué hace JSNice internamente: https://files.sri.inf.ethz.ch/website/papers/jsnice15.pdf
No funciona con mi archivo ELF
Al ejecutar
./revng artifact --analyze --progress decompile-to-single-file ../maytag.ko, apareceOnly ELF executables and ELF dynamic libraries are supported, y el archivo figura comoELF 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
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
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Ítem del roadmap: https://rev.ng/roadmap#feature-798
Pad de diseño: https://pad.rev.ng/s/eDHi2PUoP#
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 ./environmentes una mala señal. Al bajar el tar, efectivamente configuraba varias variables de entorno, incluyendo PATH, y por suerte noLD_LIBRARY_PATHLa mayoría tiene el prefijo
HARD_, que probablemente sea único, peroREVNGse vería más claro, y chocar con variables de entorno existentes es maloTambién configura
AWS_EC2_METADATA_DISABLED="true"; yo no uso AWS, así que no se rompe nada, pero en general se ve sospechosoRPATH_PLACEHOLDER,HARD_FLAGS_CXX_CLANG, un PATH largo, cadenas como mingw32/gentoo/mips, etc., se ven frágilesSi 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++, yDEFAULT_SYSROOTtambién es útilIncluso usando
rpath, si el usuario ejecuta conLD_LIBRARY_PATHconfigurado, eso puede sobrescribir elDT_RUNPATHdel binarioHoy en día
-Wl,rpathen realidad significarunpath, no rpath, y es menos útil; probablemente la invocación deseada sea-Wl,rpath -Wl,--disable-new-dtags, para que el cargador ignoreLD_LIBRARY_PATHal buscar bibliotecasCon 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-16esté enlazado dinámicamente y en tiempo de ejecución busque cosas comolibLLVMAArch64CodeGen.so.16también aumenta los modos de fallaCon
LLVM_BUILD_STATIC=ONse puede reducir el problema de que, en un entorno con toolchains de módulos HPC activados, tome bibliotecas equivocadasLas herramientas están enlazadas contra
libc++.so,libc++abi.so, etc.; valdría la pena considerar libc++ estática y, como mínimo, conviene enlazarlibc++abiylibunwindestáticamente dentro de libc++Se me agotó por completo la paciencia para distribuir programas enlazados dinámicamente en Linux
Si el
source ourhackdel 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 horriblesEn comparación, el enlace estático es realmente bueno
source environmentDe 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
./revngEn ese caso, los cambios de entorno solo afectan la invocación de
revngLa documentación está aquí: https://docs.rev.ng/user-manual/working-environment/
Sería bueno agregar una advertencia sobre
source ./environmentDedicamos 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_PATHes maldadLas variables
HARD_solo se usan en el wrapper del compilador y creo que en la práctica casi no hay posibilidad de conflictoLa 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_PLACEHOLDERyHARD_FLAGS_CXX_CLANGse usan cuando revng enlaza binarios traducidos, y si no te interesa la traducción binaria de extremo a extremo, no son importantesQueremos intencionalmente
DT_RUNPATH.DT_RPATHestá deprecado, y puede haber casos de uso en los que se necesite reemplazar nuestras bibliotecas conLD_LIBRARY_PATHCreo 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_*yREVNG_*son variables privadas y todas tienen como objetivo la traducción binariaPodrí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$ORIGINSi ejecutas
./root/bin/python ./root/bin/revng artifact --help, verás que funcionaDe nuevo,
source environmentes casi solo para demos; en el uso real basta con ejecutar./revngy el entorno queda intactoTambién distribuimos Python, pero no es obligatorio usarlo. Puedes usar
./revngo interactuar por red en modo daemonEl 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./revngMe 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/storesin permisos de rootTal vez sea mejor hablar de este tipo de discusiones en el servidor de Discord que aquí
¿Te arrepientes de haberle encargado el lifting a QEMU TCG, o funcionó bien?
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