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

Zwei Versionen eines .NET-Assemblys mit Glass.NET vergleichen

Sie haben die v1.2.0 und die v1.3.0 einer DLL und müssen genau wissen, was sich geändert hat — neue APIs, eine still veränderte Methode, ein neuer Netzwerkaufruf — ohne den Quellcode und ohne einen der beiden Builds auszuführen. So vergleichen Sie zwei Assembly-Versionen in Glass.NET, dem kostenlosen, rein statischen .NET-Decompiler.

Sie haben die v1.2.0 einer DLL, und jemand hat Ihnen gerade die v1.3.0 übergeben. Vielleicht ist es eine Abhängigkeit, die Ihr Paketmanager erhöhen will, ein Hotfix, den ein Anbieter per E-Mail schickte, oder ein NuGet-Update mit einem Changelog, das „Fehlerbehebungen und Verbesserungen” sagt. Bevor Sie ihr in Ihrem Build vertrauen, wollen Sie die ehrliche Antwort auf eine einzige Frage: Was hat sich tatsächlich geändert?

Nicht das, was die Versionshinweise behaupten. Das echte Diff — neue und entfernte Typen, ein still umgeschriebener Methodenkörper, eine verschobene öffentliche Signatur, ein Netzwerkaufruf, der in der letzten Version noch nicht da war. Und Sie wollen es ohne den Quellcode (den Sie nicht haben) und ohne einen der beiden Builds auszuführen (dem Sie noch nicht vertrauen).

Das ist eine Dekompilier-und-Vergleich-Aufgabe, und Glass.NET ist dafür gemacht. Es ist kostenlos und streng statisch — es liest Metadaten und IL und rekonstruiert C#, und führt das inspizierte Assembly nie aus. Sie können also ein Update, bei dem Sie unsicher sind, gefahrlos vergleichen: Nichts aus einer der beiden DLLs wird ausgeführt. Glass bietet einen Assembly-Vergleich nebeneinander mit einem zeilenweisen Diff, der die beiden Versionen nebeneinanderstellt und Ihnen das Delta direkt zeigt, Methode für Methode.

Warum „lies den Changelog” nicht genügt

Ein Changelog ist eine Behauptung, kein Beweis. Die ausgelieferte Binärdatei ist die Quelle der Wahrheit dafür, was ausgeführt wird, und sie weicht auf allen üblichen Wegen von der Geschichte ab:

  • Die Binärdatei ist nicht das Repository. Ein .nupkg ist ein kompiliertes Artefakt aus einem Feed. Sofern es kein nachweislich reproduzierbarer Build ist, ist die DLL — nicht das GitHub-Tag — das, was in Ihrem Prozess läuft.
  • Patch-Erhöhungen verbergen echte Änderungen. Eine „Fehlerbehebungs”-Version kann einen neuen ausgehenden Aufruf hinzufügen, ändern, wie ein Wert validiert wird, oder einen Standardwert verändern. Semantische Versionierung ist eine Konvention, keine Garantie.
  • Breaking Changes rutschen still durch. Eine öffentliche Methode, die ihre Signatur unangekündigt geändert hat oder verschwunden ist, bricht Ihre Aufrufer zur Laufzeit, selbst wenn die Versionsnummer „sichere Minor-Erhöhung” sagt.

Das Delta selbst zu lesen ist eine billige Versicherung, und es ist dieselbe Disziplin wie das Inspizieren eines NuGet-Pakets, bevor Sie ihm vertrauen — nur dass Sie der alten Version bereits vertraut haben, also nur prüfen müssen, was sich bewegt hat.

Laden Sie beide Versionen

Legen Sie beide DLLs auf die Platte. Für eine NuGet-Abhängigkeit liegen sie im globalen Paket-Cache — %USERPROFILE%\.nuget\packages\<id>\<version>\lib\<tfm>\ unter Windows, ~/.nuget/packages/... sonst — ein Ordner pro Version, sodass Sie die 1.2.0 und die 1.3.0 nebeneinander greifen können. Für eine Anbieterlieferung oder Ihre eigene Ausgabe zeigen Sie einfach auf die beiden Dateien.

Öffnen Sie das erste Assembly in Glass.NET (ziehen Sie es auf das Fenster oder Datei ▸ Assembly öffnen) und öffnen Sie dann das zweite. Jedes erscheint als Baum aus Namespaces ▸ Typen ▸ Member, mit lesbarem, bei Bedarf rekonstruiertem C# — ohne PDB, ohne Source Link, ohne speziellen Build.

Führen Sie den Assembly-Vergleich aus

Starten Sie den Assembly-Vergleich von Glass.NET und wählen Sie die beiden Versionen als alte und neue Seite. Glass dekompiliert beide und zeigt ein zeilenweises Diff des rekonstruierten C#, ausgerichtet, damit Sie den Unterschied direkt lesen, statt zwischen zwei Fenstern hin- und herzuspringen und sich auf Ihr Gedächtnis zu verlassen. Das ist der Kern des Arbeitsablaufs: Sie prüfen das Delta, Sie lesen nicht die ganze Bibliothek erneut.

Arbeiten Sie es mit konkreten Fragen durch.

1. Welche Typen und Member sind erschienen oder verschwunden?

Beginnen Sie auf der strukturellen Ebene, vor jedem Methodenkörper. Der Vergleich fördert die Typen und Member zutage, die in der v1.3.0 neu sind, daraus fehlen oder sich geändert haben. Fragen Sie, was jeder bedeutet:

  • Ein neuer Typ — besonders einer, der E/A, Serialisierung oder Prozesssteuerung berührt — ist das Erste, was zu verstehen ist. Ein Logging-Helfer ist Routine; ein neuer *Client oder *Uploader in einer Bibliothek, die keinen Grund hatte, mit dem Netzwerk zu reden, verdient einen scharfen Blick.
  • Ein entfernter Typ oder Member ist ein Kompatibilitätssignal. Wenn Ihr Code ihn referenzierte, bricht die Erhöhung Sie — besser hier erfahren als durch eine MissingMethodException zur Laufzeit.
  • Ein hinzugefügtes oder entferntes Feld an einem Typ, den Sie serialisieren, kann still die Formate auf der Platte oder auf der Leitung ändern.

2. Hat sich die öffentliche API-Oberfläche geändert?

Schränken Sie auf die öffentliche Oberfläche ein — den Vertrag, von dem alles stromabwärts abhängt. Klappen Sie die öffentlichen Typen und Member auf beiden Seiten auf und lassen Sie den Vergleich zeigen, was hinzugefügt, entfernt oder neu signiert wurde:

// v1.2.0
public Result Process(string input)

// v1.3.0
public Result Process(string input, CancellationToken token = default)

Ein so hinzugefügter optionaler Parameter ist meist quellcode-kompatibel, aber nicht binärkompatibel — Aufrufer müssen neu kompilieren, und ein gegen die alte Signatur geladenes Plugin wird fehlschlagen. Eine entfernte öffentliche Methode, ein geänderter Rückgabetyp oder ein Parameter, der seinen Standardwert verloren hat, ist ein härterer Bruch. Der Sinn, gezielt die öffentliche Oberfläche zu vergleichen, ist, dass hier eine „Minor”-Versionserhöhung den Schaden anrichtet, über den sie am wenigsten ehrlich ist.

3. Was hat sich innerhalb eines Methodenkörpers geändert?

Für eine Methode, die in beiden Versionen existiert, zeigt das zeilenweise Diff genau, wie sich ihr rekonstruiertes C# geändert hat. Hier erwischen Sie das stille Umschreiben — das, was kein Changelog erwähnt:

  • Eine Validierungsprüfung, die entfernt oder gelockert wurde.
  • Eine fest codierte Konstante, ein Limit oder ein Standardwert, der sich verschoben hat.
  • Ein neuer Zweig, der etwas aufruft — eine Datei, einen Registry-Schlüssel, eine URL.

Der wertvollste Fund hier ist ein neuer Netzwerkaufruf oder Prozessstart, den die alte Version nicht hatte. Wenn die v1.3.0 eines Datumsformatierungs-Helfers plötzlich einen HttpClient konstruiert und an einen fest codierten Endpunkt POSTet, stellt das Diff Ihnen genau diese Zeilen vor Augen. Das ist dieselbe Jagd auf Warnsignale, die das Analysieren eines verdächtigen .NET-Assemblys behandelt — das Diff grenzt sie nur auf das Neue ein.

4. Lesen Sie die IL, wo das C# mehrdeutig ist

Dekompiliertes C# ist eine Rekonstruktion, und zwei echt verschiedene Builds können gelegentlich C# erzeugen, das gleich aussieht, oder sich nur auf eine Weise unterscheiden, die die C#-Ansicht abrundet — eine geänderte Überladungsauflösung, ein Wechsel zwischen == und object.Equals, eine vom Compiler generierte Zustandsmaschine, die sich neu organisiert hat. Wenn das C#-Diff einer Methode verdächtig leer oder verdächtig laut aussieht und Sie Gewissheit brauchen, schalten Sie auf die IL-Ansicht von Glass.NET und vergleichen Sie die IL direkt. Die IL ist das, was tatsächlich läuft, also ist sie die Grundwahrheit; die IL zu lesen ist der Schiedsrichter, wenn das C# mehrdeutig ist. Für die meisten Methoden reicht das C#-Diff völlig — greifen Sie bei der Handvoll zur IL, bei der es darauf ankommt.

Nutzen Sie den Expositionsbericht als schnellen Filter

Glass.NET erzeugt außerdem einen Expositionsbericht, der zusammenfasst, wie lesbar ein Assembly ist. Lassen Sie ihn über beide Versionen laufen als schnelles Triage-Signal: Wenn die v1.3.0 plötzlich weit weniger lesbar meldet als die v1.2.0, hat eine zuvor unverschleierte Abhängigkeit vielleicht begonnen, obfuskierten oder virtualisierten Code auszuliefern — was in einer gewöhnlichen Open-Source-artigen Bibliothek bereits ein Grund ist, innezuhalten und zu fragen, warum. (Wenn Sie auf der anderen Seite davon stehen — Ihren eigenen Build schützend — dafür ist der Schwester-Obfuskator Nebula.NET da, und Code-Virtualisierung ist ein Pro-Feature; Sie würden dann das Ergebnis in Glass überprüfen.)

Kennen Sie die Grenzen

Zwei Versionen zu vergleichen sagt Ihnen genau, was sich in den Bytes geändert hat, die Sie haben — es sagt Ihnen nicht, ob eine Änderung sicher ist, nur was sie ist; dieses Urteil bleibt Ihnen. Statisches Lesen fördert kein Verhalten zutage, das nur zur Laufzeit mit bestimmten Eingaben auftritt, und stark obfuskierter Code lässt sich vielleicht auf keiner der beiden Seiten sauber rekonstruieren (auch das ein Signal für sich). Und Sie vergleichen zwei bestimmte Builds: Pinnen Sie Ihre Abhängigkeiten und vergleichen Sie bei jeder Erhöhung erneut, damit das Delta immer klein genug bleibt, um es tatsächlich zu lesen.

Genau das ist der Sinn. Statt eine ganze Bibliothek bei jeder Erhöhung neu zu prüfen, prüfen Sie nur, was sich bewegt hat — neue APIs, entfernte Member, umgeschriebene Körper, ein neuer Netzwerkaufruf — in einem kostenlosen, rein statischen Werkzeug, das nie eine Zeile eines der beiden Builds ausführt. Laden Sie Glass.NET herunter, laden Sie beide Versionen und lesen Sie das Diff, bevor Sie der neuen vertrauen.

Nebula.NET testen

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