.NET RE Tutorialserie – PatchMe 01 & 02
In diesem zweiten Teil der .NET RE Tutorialserie wird es um das sog. “patchen” (zu deutsch: flicken) gehen. Ich werde die grundlegenden Tools zum Patchen erklären, für die schon fortgeschritteneren User den Patch mit dem Hexeditor erklären und dann dürft ihr euch selbst an PatchMe #01, aus diesem Tutorial, und PatchMe #02, eine Herrausforderung, versuchen. Da dies der einzige Artikel zum direkten Patchen ist wird dieser auch entsprechend komplex und lang, habt dafür also bitte Verständnis
Patchen ist eine Datei in ihrem Ablauf so zu verändern, dass sich daraus für den Cracker ein Vorteil ergibt. So gibt es die bekannten 1-Byte-Patches, welche durch nur eine kleine Modifikation den ganzen Schutz aushebeln oder auch größere Patches wie das Entfernen von Funktionen, Strings und ganzen Routinen.
Da wir uns hier im .NET Bereich bewegen sollten zuvor nochmal ein paar Dinge geklärt werden: Der MSIL-Code, welcher aus C# und anderen .NET Sprachen übersetzt wird, wird erst zur Laufzeit in echten Maschinencode umgewandelt. Wir können also diesen MSIL-Code verändern und die .NET Assembly danach neu schreiben, sodass ein neues, ausführbares Programm entsteht. Allerdings wird hier nicht geprüft, ob der Patch einen Fehler enthält! In diesem Fall wird dann beim Ausführen dieser Funktion eine Fehlermeldung geworfen. Zum Patchen sollte man übrigens zumindest die Grundlagen der MSIL-Sprache beherrschen. Wie man sich diese am besten Aneignet ist einem selbst überlassen, ich persönlich kann Euch diesen Artikel auf Codeprojekt ans Herz legen und euch raten einfach mal selbstgeschrieben Programme in MSIL-Code anzuschauen.
Doch genug der Einführung, los gehts mit der Analyse von PatchMe 01! Wir öffnen das Programm und bekommen beim Klick auf den Button eine enttäuschende Fehlermeldung:
Wir laden das Programm in ein Decompiler unserer Wahl, dann sollten wir dieses oder ein ähnliches Bild bekommen:
Das sagt uns wie immer noch nicht viel, außer dass die Form wohl eine Variable namens bIsActivated hat! Ein Klick auf die btnCheckPatch_Click-Funktion zeigt uns folgenden Source, der wohl hoffentlich selbsterklärend ist:
private void btnCheckPatch_Click(object sender, EventArgs e) { if (this.bIsActivated) { MessageBox.Show("You did it, well done! ;)", "DONE", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); } else { MessageBox.Show("Try it again :/", "FAIL", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } |
Wenn der Button gedrückt wurde wird geprüft, ob die Variable this.bIsActivated auf True steht. Wenn nicht wird die oben abgebildete Fehlermeldung ausgegeben.
Da wir nun wissen wie das Programm arbeitet haben wir 2 Möglichkeiten zum Patchen:
- Wir suchen die Stelle in welcher bIsActivated auf FALSE gesetzt wird und ändern dieses auf True.
- Wir patchen direkt die IF-Abfrage zu einem “if (this.bIsActivated == false)”.
Bedienen wir uns zuerst der ersten Variante, danach wird die zweite Variante ohne Tools mit dem HexEditor gepachted. Wir Analysieren also mit dem Decompiler, in welcher Funktion bIsActivated auf False gesetzt wird. Unter dem .NET Reflector lautet dieser Punkt “Analyse->Assigned By”:
Doch wie kann dieser Code jetzt verändert werden? Wir bedienen uns hierzu des Reflector-Plugins Reflexil. Diese geniale Erweiterung erlaubt es uns den MSIL Code zu modifizieren, neue Member zu Klassen hinzuzufügen und noch ein paar technische Spielereien, die wir sonst nur mit größtem Aufwand erledigen könnten. Reflexil bedient sich der, schon in Post 1 erwähnten, Mono.Cecil-Libary, also wird die Assembly nach jeder Modifikation komplett neu geschrieben.
Schauen wir uns doch mal den frmMain_Load-Code unter dem Reflexil-Plugin an:
Hier werden die einzelnen OpCodes der MSIL-Sprache angezeigt und können gelöscht, modifziert oder auch hinzugefügt werden. Die Kommentare hinter den Zeilen sollten eigentlich selbsterklärend sein, aber trotzdem nochmal die Kurzform: Nachdem der This-Pointer (wie in Hochsprachen wird immer als Arg0 der eigene Pointer übergeben) geladen wird, läd das Programm 0 (False) auf den Stack. StFld (StoreField) holt sich nun diesen This-Pointer und schreibt den Wert des Stacks (0) in das angeforderte Feld. Danach wird die Funktion einfach verlassen.
Der Patch gestaltet sich also einfach, wir laden statt einer 0 eine 1 auf den Stack und voila! Dazu machen wir Rechtsklick->Edit und ändern die Instuction zu ldc.i4 1.Danach Speichern wir die Assembly unter Rechtsklick auf PatchMe1->Reflexil->Save As… Wenn ihr das ganze brav nachgemacht habt, so bekommt ihr nun eine schöne Messagebox als Belohnung zu sehen.
Der Patch im Hexeditor ist nicht viel komplexer, doch muss dazu erst ein neues Tool zur Analyse eingeführt werden: Der CFF Explorer! Dieses (wiedermal) geniale Tool zeigt für native Dateien die PE-Daten an, für .NET Binaries auch die .NET Metadata! Für weitere Informationen über den Aufbau des .NET Formats verlinke ich euch gerne auf den passenden Artikel Der CFF Explorer ließt also die Tables aus und stellt sie übersichtlich dar. Im folgenden Screenshot sieht man den Eintrag “btnCheckPatch_Click” aus der Method-Table:
Die Funktion hat also einen RVA (Relative Virtual Offset) von 000020AC. Dieser RVA als Fileoffset ergibt 2AC, an dieser Stelle sehen wir im Hex-Editor die folgenden Bytes:
Die gelbe Hintergrundfarbe zeigt das Ende der Funktion, die vor der btnCheckPatch_Click steht. Sie wird mit einem 0x2A (RET) abgeschlossen. Danach folgt der Header der btnCheckPatch_Click Funktion, in Blau markiert. Die genaue Headeraufteilung würde hier den Rahmen sprengen, daher belassen wir es so. Ab 0x2B0 (in Rot) fängt der eigentliche MSIL-Code dieser Funktion an, beginnend mit einem NOP (0×00) und einem LDARG.0 (0×02). Wer mir das nicht glaubt schaut es sich im Reflector an oder benutzt die MSIL-OpCodes Referenz! Da wir uns für den bedingten Sprung interressieren, wird wohl 0x2C bzw 0x2D für uns interessant werden… Also folgt weiter MSIL-Code bis zum grün hervorgehobenen Byte. 0x2D steht für brtrue.s, also wenn das aktuelle Argument auf dem Stack TRUE ist wird gesprungen. Hier haben wir also unseren 1-Byte-Patch, wir ändern 0x2D zu 0x2C (brfalse.s), den Rest belassen wir so. Die Funktion wird wieder mit einem 0x2A (RET) abgeschlossen und das wars.
Mit der MSIL-OpCodes Referenz ist man richtig gut gewappnet, wobei Man(n) selten MSIL-Code in direkter Byteform bearbeiten muss, dafür gibt es ja Reflexil
Diesesmal gibt es mal eine Herausforderung für Euch um das Patchen zu üben Ziel ist es den Login-Screen zu bypassen und schließlich die CheckPatch-Funktion zu überlisten. Ich gebe zu dass es nicht ganz leicht ist, aber was würdet Ihr sonst dabei lernen?
Im nächsten Artikel wird nebenbei auf dieses PatchMe #02 eingegangen, also fleißig Analysieren und Patchen.
Download:
PatchMe #01 (133)PatchMe #02 (136)
Viel Erfolg
Easy
Andere Artikel zu dieser Serie
- .NET RE Tutorialserie - Obfuscatoren und Gegenmaßnahmen (Dezember 8, 2011)
- .NET RE Tutorialserie - Video-Lösung zu PatchMe #02 (Dezember 3, 2011)
- .NET RE Tutorialserie – PatchMe 01 & 02 (This post) (November 23, 2024)
- .NET RE Tutorialserie - AnalyseMe 01 (November 10, 2024)
Hi,
schöne Ergänzung zu deinem Teil I der Tutorialserie. Gefällt mir wirklich sehr gut und habe bisher auch als Anfänger alles verstanden
Gruß
Guten Tag,
Ahm würde es auch als Lösung gelten wenn man die “Save Code”-Funktion von ILSpy benutzt hat? Ich meine es kommt ja auch das Selbe wenn ich mich nicht irre oder?
Mfg!
Naja, klar kannst Du den Code komplett abspeichern, das Projekt verändern und neu kompilieren
ABER das Problem ist halt dass in den meisten “echten” Programmen das Projekt sich nicht mehr kompilieren lässt, da vorallem Funktionsnamen und Aufrufe das ganze Projekt zerschießen. Also würde ich empfehlen die Patches direkt am Programm zu machen… =)
Vielen Dank für die Antwort! Mein Problem ist nur immoment das ich weder das Geld für den .Net Reflector noch die Geduld für das Arbeiten mit dem CFF Explorer habe… Gibt es vieleicht irgendeine kostenfreie (vlt. sogar Open Source) Lösung dafür?
Der .NET Reflector wurde bereits leaked und der Source ist verfügbar, daher gibt es sogar verschiedene “Builds” mit diversen Modifikationen. Am besten Du suchst Dir selbst eine Quelle, alternativ dazu kannst du diese Version verwenden, da ist Reflexil schon dabei. Wie vertrauenswürdig die Quelle ist kann ich aber leider nicht sagen
Das Arbeiten mit dem CFF Explorer ist in der Regel nicht nötig und Patches müssen ebenfalls fast nie direkt im Hex-Code gemacht werden. Dies war nur ein kleiner Exkurs damit man versteht was “intern” passiert.
Es gibt noch ein paar Alternativen zum Reflector, neben ILSpy ist das dotPeek (closed Source) oder auch Simple Assembly Explorer (open Source)
Interessanter Post. Sicher nicht verkehrt, sich mit der Thematik intensiver zu beschaeftigen. Werde auch die nächsten Posts lesen.