Skip to content
← Alle Beiträge
· Delta1 Labs Glass.NETDekompilierungAnleitung.NET

Eingebettete Ressourcen aus einem .NET-Assembly mit Glass.NET extrahieren und lesen

Eine DLL trägt mehr als Code. In dieselbe Datei gebacken sind eingebettete .resources und ResX-Zeichenfolgen, lokalisierte Satellitenzeichenfolgen, ganze Dateien wie Config, JSON, SQL und Zertifikate sowie Zeichenfolgen- und Byte-Konstanten. So findet und liest man all das in Glass.NET — dem kostenlosen, rein statischen Decompiler, der das Assembly nie ausführt — und exportiert es auf die Platte, um es außerhalb des Werkzeugs zu prüfen.

Ein kompiliertes .NET-Assembly ist nicht nur Code. In dieselbe Datei gebacken, neben der IL, liegt eine überraschende Menge an Daten: .resources-Zeichenfolgentabellen, kompiliert aus .resx, lokalisierte Zeichenfolgen in Satelliten-Assemblys, ganze Dateien, die jemand einzubetten beschloss — eine Config, ein JSON-Seed, ein SQL-Skript, ein Zertifikat, ein Icon — und die Zeichenfolgen- und Byte-Konstanten, die direkt in den Code geschrieben sind. Wenn Sie an das heranmüssen, was eine DLL neben ihren Methoden ausliefert, ist das das Material, auf das Sie aus sind.

Die Gründe kommen ständig auf. Sie vermuten, ein Anbieter hat eine fest codierte Verbindungszeichenfolge oder einen internen Endpunkt in einem Release-Build gelassen, und wollen es bestätigen. Sie haben den Quellcode eines alten Werkzeugs verloren und müssen die Config oder das Asset wiederherstellen, mit dem es gebaut wurde. Sie prüfen eine Abhängigkeit und wollen genau sehen, welche Dateien sie mitführt. Oder Sie wollen schlicht die lokalisierten UI-Zeichenfolgen einer Bibliothek lesen, um eine Übersetzung zu prüfen. All das steckt in der Binärdatei, lesbar ohne den Quellcode.

Glass.NET liest es. Es ist kostenlos und streng statisch — es liest Metadaten, IL und den Ressourcen-Blob und rekonstruiert C#, und führt das inspizierte Assembly nie aus. Diese Unterscheidung zählt hier mehr als irgendwo sonst: Eine eingebettete Ressource zu lesen heißt, gespeicherte Bytes aus der Datei zu lesen, nicht dem Code beim Laufen zuzusehen. Also ist es völlig sicher, Ressourcen aus einer Binärdatei zu extrahieren, die Sie nie auszuführen wagen würden — nichts in ihr läuft, wenn Sie sie öffnen, eine Ressource lesen oder sie exportieren.

Was wirklich drinsteckt

Es hilft, die Formen zu kennen, denen Sie begegnen, bevor Sie auf die Suche gehen:

.resourceskompiliert aus.resxZeichenfolgen-tabellen, UTF-8Satellitlokalisierte Stringsfr/, de/, es/ …eigenes .resourcesje Kultureingeb. DateienConfig · JSONSQL · ZertsBilder, Blobsexakte BytesKonstantenString-Literalebyte[]-Arraysin der IL,im C#

Die ersten drei sind verwaltete Ressourcen, gespeichert im Assembly-Manifest; die vierte lebt in der IL selbst und taucht im dekompilierten C# auf. Glass behandelt beide, auf leicht unterschiedlichen Wegen.

Öffnen Sie das Assembly

Finden Sie zuerst die DLL. Für eine NuGet-Abhängigkeit liegt sie im globalen Paket-Cache — %USERPROFILE%\.nuget\packages\<id>\<version>\lib\<tfm>\ unter Windows, ~/.nuget/packages/... sonst. Für eine Anbieterlieferung oder einen alten Build von Ihnen liegt sie dort, wo sie gelandet ist, meist in bin/. Öffnen Sie sie in Glass.NET, indem Sie sie auf das Fenster ziehen, oder Datei ▸ Assembly öffnen. Eine schlichte verwaltete .dll genügt — kein PDB, kein Quellcode. Und weil Öffnen und Lesen statisch sind, ist eine Binärdatei, der Sie nicht vertrauen, sicher zu öffnen: Glass führt sie nie aus.

Finden Sie die Ressourcen im Baum

Klappen Sie das Assembly auf und gehen Sie zu seinem Ressourcen-Knoten — er sitzt neben dem Namespace ▸ Typen ▸ Member-Baum. Glass listet jede eingebettete Ressource, die das Manifest deklariert: die aus .resx kompilierten .resources-Streams und jede rohe Datei, die der Autor eingebettet hat. Diese Liste allein ist aufschlussreich. Ein Strings.resources ist erwartbar; ein appsettings.Production.json, ein migrations.sql, ein private.pfx oder ein unerklärtes .bin ist genau das, wofür Sie das Assembly geöffnet haben.

Wählen Sie einen .resources-Stream, und Glass zeigt seine Zeichenfolgentabelle — die Ressourcennamen und ihre Werte — sodass Sie die eingebetteten Zeichenfolgen direkt lesen können: Fehlermeldungen, Vorlagen, UI-Beschriftungen und die gelegentliche Verbindungszeichenfolgen-Vorlage, die jemand in einer Ressource statt in der Config geparkt hat. Wählen Sie eine rohe eingebettete Datei, und Sie können ihren Inhalt an Ort und Stelle prüfen; bei einer Textdatei wie JSON oder SQL reicht das oft schon zum Lesen.

Für lokalisierte Zeichenfolgen liegen die kulturspezifischen Werte gar nicht in der Haupt-DLL — sie liegen in Satelliten-Assemblys, einer MyApp.resources.dll unter einem Kulturordner wie fr/ oder de/. Ein Satellit ist einfach ein Assembly mit eigenem .resources-Stream, also öffnen Sie ihn in Glass genauso, wie Sie das Haupt-Assembly geöffnet haben, und lesen Sie seine Zeichenfolgentabelle auf dieselbe Weise. So prüfen Sie, was eine gegebene Übersetzung tatsächlich ausliefert.

Lesen Sie die Zeichenfolgen- und Byte-Konstanten im Code

Nicht alles „Eingebettete” ist eine verwaltete Ressource. Ein fest codierter Endpunkt, ein Standardpasswort, ein Lizenz-Salt oder ein eingebettetes Byte-Array lebt oft als Konstante im Code — ein String-Literal oder ein byte[]-Initialisierer in der IL, kein Eintrag im Ressourcen-Blob. Diese treten zutage, wenn Sie den Typ dekompilieren: Klicken Sie den Member an und lesen Sie das rekonstruierte C#, und das Literal steht direkt im Quellcode. Um nach ihnen zu fegen, dekompilieren Sie den relevant wirkenden Typ und lesen ihn, oder nutzen Sie Alle Verweise suchen (Shift+F12) auf der API, die den Wert konsumiert — jedes new SqlConnection, jede HttpClient-Basisadresse — um auf jedem Aufrufort zu landen und das Literal im Kontext zu sehen. So kommt eine Verbindungszeichenfolge, die ein Anbieter in einem const string „versteckt” hat, geradewegs heraus. (Wie man eine .NET-DLL zu C# dekompiliert deckt den Leseablauf vollständig ab.)

Exportieren Sie in ein Projekt, um die Dateien auf der Platte zu haben

Eine Ressource im Baum zu lesen beantwortet „was ist hier drin?”. In dem Moment, in dem Sie die Ressourcendateien selbst wollen — um ein Zertifikat in Ihrem eigenen Werkzeug zu öffnen, ein SQL-Skript durch einen echten Client zu schicken, eine wiederhergestellte Config gegen die aktuelle zu vergleichen oder einen JSON-Seed in einen Test zu füttern — wollen Sie sie auf die Platte geschrieben, außerhalb von Glass, als gewöhnliche Dateien. Das tut der Export.

Datei ▸ In Projekt exportieren rekonstruiert das ganze Assembly zu einer baubaren .csproj und extrahiert die eingebetteten Ressourcen neben dem Quellcode — die .resources und die rohen eingebetteten Dateien werden als Dateien in den Projektordner geschrieben. Aus einem Skript tut der Unterbefehl glass export dasselbe ohne Oberfläche:

glass export Vendor.Sync.dll --output ./Vendor.Sync.Source

Jetzt liegen die Ressourcen auf der Platte neben dem rekonstruierten .cs, und Ihre gewohnten Werkzeuge sind zurück: Öffnen Sie den Ordner, greppen Sie die extrahierten Dateien nach einem vermuteten Geheimnis, laden Sie das Zertifikat, führen Sie das SQL aus. Weil der Export weiterhin statische Rekonstruktion ist, hat er die Binärdatei nie ausgeführt, um irgendetwas davon zu erzeugen — Sie können eine nicht vertrauenswürdige DLL exportieren und ihre Fracht ganz zu Ihren eigenen Bedingungen prüfen. Die ausführliche Betrachtung des Exports, einschließlich dessen, wo ein großes Assembly einen kurzen manuellen Durchgang braucht, steht in eine DLL zurück in ein baubares Projekt verwandeln.

Der ehrliche Teil: gespeichert ist nicht geschützt

Alles oben Genannte funktioniert, weil die CLR eingebettete Ressourcen nicht verschlüsselt. Eine .resources-Zeichenfolgentabelle ist UTF-8-Text mit Längenpräfixen; eine rohe eingebettete Datei sind ihre exakten Bytes; eine Konstante ist ein Literal in der IL. Der eigene ResourceReader des Frameworks und GetManifestResourceStream existieren, um das zu durchlaufen, und jeder Ressourcen-Viewer — Glass eingeschlossen — ist eine Fassade über denselben gespeicherten Daten. „Ich habe es in die DLL eingebettet” ist nicht dasselbe wie „ich habe es geschützt”. Es zu lesen ist ein Doppelklick, kein Knacken.

Die praktische Folge schneidet nach beiden Seiten. Wenn Sie die Binärdatei eines anderen prüfen, heißt das, die Fracht ist trivial wiederherstellbar, was einen statischen Leser gerade nützlich macht — siehe ein NuGet-Paket prüfen, bevor Sie ihm vertrauen für den breiteren Prüfablauf. Aber richten Sie das Objektiv auf Ihre eigenen ausgelieferten Assemblys: Wenn Sie Glass auf Ihren Release-Build richten und eine lebende Verbindungszeichenfolge, einen API-Schlüssel oder ein Zertifikat in einer Ressource oder einem const finden, ist das ein Befund, keine Kuriosität. Behandeln Sie es, wie Sie jedes geleakte Anmeldedatum behandeln würden — rotieren Sie das Geheimnis und holen Sie es aus der Binärdatei. Ein Geheimnis in einem Assembly auszuliefern heißt, es an jeden auszuliefern, der das Assembly herunterlädt.

Wenn Sie wirklich Daten in der Binärdatei mitführen müssen, die Sie lieber nicht im Klartext herausgeben — eine lizenzierte Datendatei, Vorlagen, die Sie als proprietär betrachten — dann verdient sich der Schwester-Obfuskator Nebula.NET hier seinen Platz: Er kann eingebettete Ressourcen und Zeichenfolgen zur Bauzeit verschlüsseln und transparent hinter Ihren bestehenden Aufrufen von ResourceManager und GetManifestResourceStream entschlüsseln, sodass ein Ressourcen-Viewer Chiffretext statt Ihres SQL sieht. Die ausführliche Betrachtung dazu ist eingebettete Ressourcen verschlüsseln, und die passende Behandlung für Literale im Code ist Zeichenfolgenverschlüsselung in .NET. Das ist Standard-Nebula-Schutz — Ressourcen- und Zeichenfolgenverschlüsselung, keine hohe Stufe. Aber seien Sie klar darüber, was es bringt: Es hebt die Wiederherstellung von „lesen” auf „rückentwickeln”. Es macht ein Geheimnis, das Sie bereits ausgeliefert haben, nicht sicher. Ein rotiertes Geheimnis ist die Behebung; Verschlüsselung ist, wie Sie vermeiden, das nächste im Klartext auszuliefern.

Der Punkt

Eine DLL liefert ihre Ressourcen so unverhüllt aus wie ihren Code. Öffnen Sie sie in Glass.NET, klappen Sie den Ressourcen-Knoten auf, um die .resources, Satellitenzeichenfolgen und eingebetteten Dateien zu listen, lesen Sie die Zeichenfolgen und prüfen Sie die Dateien an Ort und Stelle, dekompilieren Sie die Typen, um die in die IL gebackenen Konstanten zu erwischen, und exportieren Sie in ein Projekt, wenn Sie die Dateien auf der Platte wollen, um sie außerhalb des Werkzeugs zu prüfen. In Minuten können Sie eine verlorene Config wiederherstellen, die Fracht einer Abhängigkeit lesen oder den vermuteten fest codierten Endpunkt bestätigen — alles ohne eine einzige Zeile auszuführen, denn eine gespeicherte Ressource zu lesen heißt, Bytes zu lesen, nicht Verhalten. Und wenn das, was Sie finden, ein Geheimnis in Ihrem eigenen Build ist, haben Sie den Fehler gefunden, der sich zu beheben lohnt. Laden Sie Glass.NET herunter, öffnen Sie das Assembly und sehen Sie, was es wirklich mit sich trägt.

Nebula.NET testen

Härten Sie Ihren .NET-Code in wenigen Minuten — starten Sie mit der kostenlosen Edition.