Skip to content
← Todas las publicaciones
· Delta1 Labs Descompilación.NETGuía

Descompilar ensamblados ReadyToRun (R2R): por qué el código nativo precompilado se descompila sin problemas

Las imágenes ReadyToRun llevan código nativo precompilado y, aun así, se descompilan a C# con la misma facilidad que cualquier ensamblado, porque el IL sigue ahí. Esto es lo que R2R guarda realmente, cómo reconocerlo y por qué un descompilador ignora la parte nativa.

Si alguna vez te han pasado un ensamblado .NET «precompilado» y diste por hecho que un descompilador se atascaría con él, ReadyToRun es la grata sorpresa. R2R es la forma en que .NET entrega código de arranque rápido — las propias bibliotecas del runtime son R2R, y PublishReadyToRun=true lo activa para tus apps e imágenes de contenedor — y suena a que debería frustrar la descompilación, porque contiene código nativo compilado AOT. No lo hace. Un ensamblado R2R se descompila a C# limpio porque lo único que R2R nunca descarta es el IL. Entender por qué hace que toda una categoría de preguntas «¿puedo leer esto?» resulte fácil de responder.

Qué contiene realmente una imagen R2R

Un ensamblado .NET normal es metadatos + IL, compilado a código nativo por el JIT en la primera ejecución. Una imagen R2R la produce crossgen2, que ejecuta ese JIT por adelantado y guarda el código nativo resultante en el ensamblado, para que el runtime pueda saltarse el JIT al arrancar. Y lo esencial: guarda el código nativo además de, no en lugar de, los metadatos y el IL originales.

Así que el archivo PE contiene tres cosas que aquí importan: las tablas de metadatos ECMA-335 (tipos, métodos, firmas, intactas), los cuerpos de método en IL (también presentes) y una sección ReadyToRun con el código nativo precompilado más las tablas que el runtime necesita para usarlo. Una ReadyToRunHeader, accesible a través del directorio de cabecera gestionada-nativa de la cabecera CLI, lo enlaza todo y marca la imagen como R2R.

An R2R PE keeps metadata and IL alongside native code Ensamblado R2R (un archivo PE): Metadatos + IL(intactos — lo que lees) Sección ReadyToRuncódigo nativo precompilado Cabecera R2Rmarca la imagen Descompilador → lee IL → C# La sección nativa es la vía rápida del runtime; el descompilador la ignora.

Por qué el descompilador ignora la parte nativa

Un descompilador como Glass es un reconstructor de IL a C#: recorre las tablas de metadatos para recuperar tipos y firmas, y luego lee el cuerpo IL de cada método y lo eleva de nuevo a C#. El código nativo de R2R vive en una sección aparte con sus propias tablas de búsqueda, y el descompilador simplemente no la consulta: el IL es la definición autorizada y portable de cada método, y sigue ahí mismo. Por eso abrir una imagen R2R es, desde el punto de vista del descompilador, indistinguible de abrir un ensamblado solo-JIT: los mismos metadatos, el mismo IL, el mismo C# de salida.

Por eso puedes descompilar las bibliotecas del runtime de .NET (que se entregan como R2R), una app con PublishReadyToRun o una imagen de contenedor con crossgen sin ningún tratamiento especial. La preocupación de «está precompilado» es por los bytes nativos, y no son lo que lee un descompilador.

Reconocer R2R, y la única excepción real

Para confirmar que un ensamblado es R2R, busca la cabecera ReadyToRun (las herramientas lo etiquetan como «ReadyToRun» y suelen mostrar un número de versión R2R), o simplemente conoce su origen: crossgen2 / PublishReadyToRun. Que el IL esté presente es la garantía de que puedes descompilarlo.

La excepción que despista es NativeAOT, que suena parecido pero es el caso opuesto. NativeAOT compila toda la app a un ejecutable nativo autónomo sin IL ni metadatos gestionados que recuperar: no hay nada que un descompilador de IL pueda leer. La prueba rápida: si una herramienta puede cargar el archivo como ensamblado .NET, es gestionado (IL normal o R2R) y se descompila; si es solo un binario nativo, es NativeAOT y tienes entre manos un trabajo de desensamblador nativo, no de descompilación. (Para cómo afecta esto a tu modelo de amenazas como proveedor, consulta proteger el código .NET de la descompilación.)

Cómo hacerlo con Glass

Glass abre los ensamblados ReadyToRun de forma transparente: lee el IL intacto y reconstruye C#, ignorando la sección nativa R2R, así que las bibliotecas del runtime, un servicio procesado con crossgen o una app con PublishReadyToRun se leen como cualquier otro ensamblado. Es el mismo flujo que descompilar una DLL a C#; R2R simplemente no se interpone.

Glass es gratuito: apúntalo a una imagen R2R y verás el IL volver como C#.

Prueba Nebula.NET

Endurece tu código .NET en minutos — empieza con la edición gratuita.