Extrae y lee recursos embebidos de un ensamblado .NET con Glass.NET
Una DLL lleva más que código. Horneados en el mismo archivo hay recursos .resources y cadenas ResX embebidas, cadenas localizadas de ensamblados satélite, archivos enteros como config, JSON, SQL y certificados, y constantes de cadena y de bytes. Así se encuentra y se lee todo en Glass.NET — el decompilador gratuito y de solo análisis estático que nunca ejecuta el ensamblado — y se exporta a disco para inspeccionarlo fuera de la herramienta.
Un ensamblado .NET compilado no es solo código. Horneada en el mismo archivo, junto al IL, hay una cantidad sorprendente de datos: tablas de cadenas .resources compiladas desde .resx, cadenas localizadas en ensamblados satélite, archivos enteros que alguien decidió embeber — un config, una semilla JSON, un script SQL, un certificado, un icono — y las constantes de cadena y de bytes escritas directamente en el código. Cuando necesitas llegar a lo que una DLL distribuye además de sus métodos, ese es el material que buscas.
Los motivos surgen constantemente. Sospechas que un proveedor dejó una cadena de conexión o un endpoint interno codificado a fuego en una compilación de lanzamiento, y quieres confirmarlo. Perdiste el código fuente de una herramienta vieja y necesitas recuperar el config o el recurso con el que se compiló. Estás evaluando una dependencia y quieres ver exactamente qué archivos lleva. O simplemente quieres leer las cadenas de interfaz localizadas de una biblioteca para revisar una traducción. Todo eso está en el binario, legible sin el código fuente.
Glass.NET lo lee. Es gratuito, y es estrictamente estático — lee los metadatos, el IL y el blob de recursos y reconstruye C#, y nunca ejecuta el ensamblado que inspecciona. Esa distinción importa aquí más que en ningún otro sitio: leer un recurso embebido es leer bytes almacenados del archivo, no ver cómo se ejecuta el código. Así que extraer recursos de un binario que jamás te atreverías a ejecutar es del todo seguro — nada en él se ejecuta cuando lo abres, lees un recurso o lo exportas.
Qué hay ahí dentro de verdad
Ayuda conocer las formas que te vas a encontrar antes de ir a buscar:
Las tres primeras son recursos gestionados, almacenados en el manifiesto del ensamblado; la cuarta vive en el propio IL y aparece en el C# decompilado. Glass gestiona ambas, por rutas ligeramente distintas.
Abre el ensamblado
Primero encuentra la DLL. Para una dependencia de NuGet está en la caché global de paquetes — %USERPROFILE%\.nuget\packages\<id>\<version>\lib\<tfm>\ en Windows, ~/.nuget/packages/... en el resto. Para una entrega de proveedor o una compilación vieja tuya, está donde haya caído, normalmente en bin/. Ábrela en Glass.NET arrastrándola a la ventana, o Archivo ▸ Abrir ensamblado. Basta con una .dll gestionada corriente — sin PDB, sin código fuente. Y como abrir y leer son estáticas, un binario en el que no confías es seguro de abrir: Glass nunca lo ejecuta.
Encuentra los recursos en el árbol
Despliega el ensamblado y ve a su nodo de recursos — se sitúa junto al árbol de espacios de nombres ▸ tipos ▸ miembros. Glass lista cada recurso embebido que declara el manifiesto: los flujos .resources compilados desde .resx y cualquier archivo crudo que el autor haya embebido. Esta lista por sí sola es informativa. Un Strings.resources es esperable; un appsettings.Production.json, un migrations.sql, un private.pfx o un .bin sin explicación es justo lo que abriste el ensamblado para encontrar.
Selecciona un flujo .resources y Glass muestra su tabla de cadenas — los nombres de recurso y sus valores — así que puedes leer directamente las cadenas embebidas: mensajes de error, plantillas, etiquetas de interfaz y la ocasional plantilla de cadena de conexión que alguien aparcó en un recurso en vez de en el config. Selecciona un archivo embebido crudo y puedes inspeccionar su contenido sobre la marcha; para un archivo de texto como JSON o SQL, a menudo eso es todo lo que necesitas para leerlo.
Para las cadenas localizadas, los valores específicos de cultura no están en la DLL principal en absoluto — están en ensamblados satélite, una MyApp.resources.dll bajo una carpeta de cultura como fr/ o de/. Un satélite es simplemente un ensamblado con su propio flujo .resources, así que ábrelo en Glass igual que abriste el principal y lee su tabla de cadenas de la misma manera. Así compruebas qué distribuye de verdad una traducción dada.
Lee las constantes de cadena y de bytes en el código
No todo lo «embebido» es un recurso gestionado. Un endpoint codificado a fuego, una contraseña por defecto, una sal de licencia o un array de bytes embebido suelen vivir como constante en el código — un literal de cadena o un inicializador byte[] en el IL, no una entrada en el blob de recursos. Estos afloran cuando decompilas el tipo: haz clic en el miembro y lee el C# reconstruido, y el literal está ahí mismo en el código. Para barrerlos, decompila el tipo que parezca relevante y léelo, o usa Buscar todas las referencias (Shift+F12) sobre la API que consume el valor — cada new SqlConnection, cada dirección base de HttpClient — para aterrizar en cada sitio de llamada y ver el literal en contexto. Así sale directa una cadena de conexión que un proveedor «escondió» en un const string. (Cómo decompilar una DLL de .NET a C# cubre el flujo de lectura completo.)
Exporta a un proyecto para tener los archivos en disco
Leer un recurso en el árbol responde a «¿qué hay aquí?». En el momento en que quieres los archivos de recurso en sí — para abrir un certificado en tu propia herramienta, pasar un script SQL por un cliente real, comparar un config recuperado con el actual, o alimentar una semilla JSON a un test — los quieres escritos en disco, fuera de Glass, como archivos corrientes. Eso es lo que hace la exportación.
Archivo ▸ Exportar a proyecto reconstruye todo el ensamblado a un .csproj compilable, y extrae los recursos embebidos junto al código — los .resources y los archivos embebidos crudos se escriben como archivos en la carpeta del proyecto. Desde un script, el subcomando glass export hace lo mismo sin interfaz:
glass export Vendor.Sync.dll --output ./Vendor.Sync.Source
Ahora los recursos están en disco junto al .cs reconstruido, y recuperas tus herramientas habituales: abre la carpeta, haz grep en los archivos extraídos buscando un secreto sospechado, carga el certificado, ejecuta el SQL. Como la exportación sigue siendo reconstrucción estática, nunca ejecutó el binario para producir nada de ello — puedes exportar una DLL no confiable e inspeccionar su carga por completo en tus propios términos. El análisis a fondo de la exportación, incluido dónde un ensamblado grande necesita un breve repaso manual, está en convertir una DLL de vuelta en un proyecto compilable.
La parte honesta: almacenado no es protegido
Todo lo anterior funciona porque el CLR no cifra los recursos embebidos. Una tabla de cadenas .resources es texto UTF-8 con prefijos de longitud; un archivo embebido crudo son sus bytes exactos; una constante es un literal en el IL. El propio ResourceReader del framework y GetManifestResourceStream existen para recorrer esto, y cualquier visor de recursos — Glass incluido — es un frontal sobre los mismos datos almacenados. «Lo embebí en la DLL» no es lo mismo que «lo protegí». Leerlo es un doble clic, no un descifrado.
La consecuencia práctica corta por los dos lados. Cuando auditas el binario de otro, significa que la carga es trivialmente recuperable, que es justo lo que hace útil a un lector estático — mira inspeccionar un paquete NuGet antes de confiar en él para el flujo de evaluación más amplio. Pero vuelve la lente hacia tus propios ensamblados distribuidos: si apuntas Glass a tu compilación de lanzamiento y encuentras una cadena de conexión viva, una clave de API o un certificado en un recurso o en un const, eso es un hallazgo, no una curiosidad. Trátalo como tratarías cualquier credencial filtrada — rota el secreto y sácalo del binario. Distribuir un secreto en un ensamblado es distribuirlo a todo el que descargue el ensamblado.
Si de verdad debes llevar en el binario datos que preferirías no entregar en claro — un archivo de datos con licencia, plantillas que consideras propietarias — ahí es donde el ofuscador hermano Nebula.NET se gana su sitio: puede cifrar recursos y cadenas embebidos en tiempo de compilación y descifrarlos de forma transparente detrás de tus llamadas existentes a ResourceManager y GetManifestResourceStream, de modo que un visor de recursos vea texto cifrado en vez de tu SQL. El análisis a fondo de eso es cifrar recursos embebidos, y el tratamiento equivalente para los literales en el código es cifrado de cadenas en .NET. Esto es protección estándar de Nebula — cifrado de recursos y de cadenas, no un nivel alto. Pero ten claro qué te compra: sube la recuperación de «leer» a «aplicar ingeniería inversa». No vuelve seguro un secreto que ya distribuiste. Un secreto rotado es la corrección; el cifrado es cómo evitas distribuir el siguiente en claro.
La idea
Una DLL distribuye sus recursos con la misma llaneza que su código. Ábrela en Glass.NET, despliega el nodo de recursos para listar los .resources, las cadenas satélite y los archivos embebidos, lee las cadenas e inspecciona los archivos sobre la marcha, decompila los tipos para pillar las constantes horneadas en el IL, y exporta a un proyecto cuando quieras los archivos en disco para inspeccionarlos fuera de la herramienta. En minutos puedes recuperar un config perdido, leer la carga de una dependencia o confirmar el endpoint codificado a fuego que sospechabas — todo sin ejecutar una sola línea, porque leer un recurso almacenado es leer bytes, no comportamiento. Y si lo que encuentras es un secreto en tu propia compilación, has encontrado el fallo que merece la pena corregir. Descarga Glass.NET, abre el ensamblado y mira qué lleva de verdad.
Prueba Nebula.NET
Endurece tu código .NET en minutos — empieza con la edición gratuita.