crackme#8

Ich muss gestehen, dass ich dieses Crackme schon vor einem halben Jahr auf crackmes.de veröffentlicht habe. Damals hatte ich leider vergessen es auch hier hochzuladen, was ich sonst immer gemacht habe. Da die Seite crackmes.de derzeit down und die Lösung somit nicht mehr verfügbar ist, hole ich das jetzt nach. Als kleinen Anzeiz gibt es den Quellcode für die gültige Serial für mucki.
(Tipp, da mehrere Lösungen richtig sind: es kommen zwei Gleichheitszeichen darin vor)
 
Zuletzt bearbeitet:
Habs bis jetzt eigentlich immer nur anhand von Tutorials nachvollzogen, deswegen hab ich nicht soviel Erfahrung...

Die Valid Serial Ausgabe bringt mich bis jetzt nicht weiter, die wird ja einfach nur ausgegeben wenn Name = Serial. Ist also wohl ein Fake, wobei davor auch bestimmt wird ob Valid oder Invalid ausgegeben wird. Aber Valid Serial sollte ja trotzdem rauskommen wenn die Serial wirklich Valid ist. Das könnte natürlich irgendwo in der tatsächlichen Überprüfung stattfinden...muss ich nachher nochmal schauen.
 
Scheint definitiv über meine aktuellen Kenntnisse hinaus zu gehen :D.

Name = Serial klappt nur innerhalb des Debuggers, wenn man die crackme so startet klappt das ganze nicht. Die Anti-Anti-Debugger Plugins bringen irgendwie nix und wenn ich das ganze in Olly geladen habe steht dort bereits der Code der nur überprüft ob Name = Serial.
 
Der Anti-Debugger-Trick ist eigentlich ganz einfach. Allerdings befindet er sich im TLS-Bereich, sodass er schon beim Laden des Crackmes in Olly ausgeführt wird.
 
Das hab ich mir gedacht, dass es schon beim Laden in Olly passiert. Muss ich mal schauen wie man das umgehen kann....wenn ich den Prozess einfach "Attache" stürzt Olly samt Crackme ab :-(
 
Mit dem Programm LordPE kannst du sehen, bei welcher Adresse sich der TLS-Bereich befindet. Diesen Bereich einfach mal anschauen und die entsprechende Stelle patchen, sodass der Anti-Debugger-Trick deaktivert wird. (Wenn ein Debugger gefunden wurde, dann wird der Aufruf von strcmp nicht auf eine andere Adresse umgeleitet.)
 
OK. Der Patch war dann recht einfach. Hab auch mal jetzt OllyDBG Version 2 runtergeladen dort funktioniert dein "Trick" irgendwie erst gar nicht.
Darf ich mal fragen warum der überhaupt funktioniert oder was da noch vorher gemacht wird oder wo mein Denkfehler ist ?

Ich habs in V1 angeschaut:
Code:
MOV EAX, crackme8.<ModuleEntryPoint>  => 401000
MOV AL, BYTE PTR DS: [EAX]                => erstes Byte bei 401000 = 6A
CMP AL,0CC                                      => AL = CC Wieso???
In V2:
Code:
MOV EAX, crackme8.<ModuleEntryPoint>  => 401000
MOV AL, BYTE PTR DS: [EAX]                => erstes Byte bei 401000 = 6A
CMP AL,0CC                                      => AL = 6A macht Sinn :-)

Ich verstehs einfach nicht :D. Wenn ich EAX einfach mal per Hand (in V1) auf 401002 Stelle dann schiebt er beim Mov Befehl auch das richtige Byte rein nur nicht bei 401000 also beim EP.

Also was da an für sich danach passiert habe ich schon verstanden nur ich verstehe einfach nich warum da ein Byte in das Register geschoben wird, dass überhaupt gar nicht dort so steht.
 
Zuletzt bearbeitet:
OK. Der Patch war dann recht einfach. Hab auch mal jetzt OllyDBG Version 2 runtergeladen dort funktioniert dein "Trick" irgendwie erst gar nicht.
OllyAdvanced als Plugin für 1.10 sollte das gleiche bewirken ;)

Ich verstehs einfach nicht :D. Wenn ich EAX einfach mal per Hand (in V1) auf 401002 Stelle dann schiebt er beim Mov Befehl auch das richtige Byte rein nur nicht bei 401000 also beim EP.

Also was da an für sich danach passiert habe ich schon verstanden nur ich verstehe einfach nich warum da ein Byte in das Register geschoben wird, dass überhaupt gar nicht dort so steht.
CC ist ein Opcode für INT3 == Software Breakpoint;)
INT (x86 instruction) - Wikipedia, the free encyclopedia
Um im Programmmodul zu stoppen, setzt Olly an den EntryPoint einen normalen INT3=0xCC Breakpoint.
Die Anzeige von Olly selbst "maskiert" allerdings die vom Nutzer/Olly gesetzten INT3s und zeigt stattdessen Originalcode/Opcode an.

Im Übrigen können auch andere Anweisungen genutzt werden (wie in modifizierten Ollys - 0xFA, 0xFB == cli und sti) - hauptsache es gibt bei der Ausführung eine "priviledge instruction" Exception.
 
Da du den Anti-Debugger-Trick entfernt hast noch ein Hinweis, damit du an den Algorithmen nicht verzweifelst. Es handelt sich dabei um gängige Kryptographie, die du mit dem Krypto-Analyzer-Plugin von PEID herausfinden kannst.
Ansonsten schau an welche Stelle die Serial geschrieben wird, was die maximale Länge ist und was man damit alles anstellen kann. :wink:
 
Ich muss mir nochmal was schlaues überlegen, aber hier schon mal eine gültige Kombination.

Name: [lmbC
Serial: 1234
 
Stimmt, so kann man es auch machen. Diese Lösung hatte ich aber gar nicht geplant. Meine Lösung sieht so aus, dass durch eine zu lange Serial die Adresse des Exceptionhandlers auf 402123 gepatcht und durch eine Division durch Null ein Fehler erzeugt wird.
 
So jetzt hab ich wieder Zeit :-).

Mein Problem ist aber ich bin einfach zu unerfahren damit (bis jetzt). PEID findet eine BASE64 Table und sagt was von CRC32...aber weiterbringen tut mich das nich :D.

Die Stellen wo mit dem Usernamen und der Serial "hantiert" wird habe ich gefunden nur hab ich einfach keinen Überblick darüber, wie das Zusammenspiel von Serial + Usernamen ist. Ich weiß nur das am Ende von beiden EAX = 0x00000000 sein muss. Dabei werd ich noch mehr verwirrt von der Kombination die ReDox gepostet hat, weil durch [lmbC, jedesmal in der Methode vom Usernamen nach der Schleife EAX = 0xFFFFFFFF ist und damit NOT EAX natürlich 0x00000000 und danach passiert damit nichts mehr und deswegen funktioniert auch jede beliebige Serial mit dem Usernamen.

Die Serial darf auch nur 8 Zeichen lang sein, also wohl 2 DWORDs. Aber wirklich weiter bin ich nicht gekommen. Naja vielleicht crackt es ja doch noch jemand anderes und kann es mir dann erklären :-)
 
Der Key-Check sieht so aus:
Code:
CRC32_Name % (CRC32_Name ^ UnknownHash_Serial) + CRC32_Name / (CRC32_Name ^ CustomHash_Serial)

Jetzt ist CRC32("[lmbC") aber Null, dadurch ist der Check auch immer Null => Gültige Kombination.

Eigentlich gesucht ist ein Serial in der Form: aaaaaaaaah#!@. Und (CRC32_Name ^ UnknownHash_Serial) muss 0 ergeben um eine Exception zu erzeugen. Habe aber noch keine Kombination gefunden, die das erfüllt. Man müsste sich die UnknownHash Funktion mal genauer anschauen, vielleicht ist hier ja was zu holen.

Ich dachte der Buffer Overflow wäre ein "Programmierfehler" und wollte ihn mir später nochmal anschauen. :D

muckie
jets0Aaa@h#!@
 
Zuletzt bearbeitet:
Ich hab wie gesagt das Problem, dass ich mich noch verdammt schwer tue damit die zusammenhänge zu sehen.

Code:
CRC32_Name % (CRC32_Name ^ UnknownHash_Serial) + CRC32_Name / (CRC32_Name ^ CustomHash_Serial)

Ist UnknownHash und CustomHash wirklich was unterschiedliches???

Also der CRC32_Name wird in EAX gespeichert und der Hash doch in ECX soweit ich weiß. ECX wird durch die Hash-Funktion und dem anschließenden Befehl
Code:
Address   Hex dump          Command                                  Comments
004018A6  |.  AB            |STOS DWORD PTR ES:[EDI]
in 40745D gespeichert und nachher wieder reingeladen und EAX ist einfach "übrig" aus dem Call
Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
00402037  |.  E8 80F8FFFF   CALL 004018BC                            ; \crackme8.004018BC

Dadurch rechnet das hier doch:
Code:
Address   Hex dump          Command                                  Comments
00402054  |.  33C8          XOR ECX,EAX
00402056  |.  33D2          XOR EDX,EDX
00402058  |.  F7F1          DIV ECX
0040205A  |.  03C2          ADD EAX,EDX
CRC32 ^ Hash ...dann folgt EDX leeren und dann eine Division durch ECX, also CRC32 / (CRC32 ^ Hash) und da in EDX der Restwert abgespeichert wird sieht es dann eigentlich so aus wie bei dir:
Code:
CRC32 / (CRC32 ^ Hash) + CRC32 % (CRC32 ^ Hash)

Diese Funktion ist also nur = 0 wenn der CRC32 = 0 ist. Die Lösung ist jetzt, sowie ich es verstanden habe, eine Serial zu finden die zu dem CRC von dem Usernamen "mucki" einen Hash erstellt, wo gilt: CRC32("mucki") ^ (Hash(x) = 0, wobei x gesucht wird.

Hab ich das soweit erstmal richtig verstanden?

Und was bringt einem das eintragen einer zu langen Serial? Abgesehen davon, dass es abstürzt :D ? Soll ich etwa den Buffer Overflow ausnutzen um an eine andere Stelle zu returnen?

Achso, übrigens: Du scheinst es ja jetzt rauszuhaben: Es wird die Serial für "mucki" gesucht nicht für "muckie" :D
 
Zuletzt bearbeitet:
UnknownHash und CustomHash soll das gleiche sein. Hatte es nur an einer Stelle umbenannt. Soweit hast Du alles richtig verstanden.
Was passiert, wenn man durch Null teilt? Richtig, es wird eine Exception geworfen. Hier wird mittels SetUnhandledExceptionFilter ein Handler registriert, der in diesem Fall aufgerufen wird. Der Buffer für den Serial ist ein paar Bytes zu kurz und befindet sich direkt vor dem gehookten lstrcmpA. Man kann also die ersten Bytes von lstrcmpANext (Die Callbackfunktion für den Hook) überschreiben. Zufällig wird genau am Anfang die Adresse des Exceptionhandlers auf den Stack gepusht. Wir ändern den Exceptionhandler auf 0x402123. Der neue Handler checkt nur, ob ein Zeichen unseres Serials stimmt.

mucki
pgqXA9==@h#!@

Scheint aber leider nicht das PW für die ZIP zu sein.

Edit:
Das Passwort ist der erste Serial mit zwei = der generiert wurde.

pgqXAw==@h#!@
 
Zuletzt bearbeitet:
OK soweit so gut. Also dient: pgqXA8== für Hash = CRC32, damit CRC32 ^ Hash = 0 ist. Die Zeichen: h#!@ sind dann (in HEX) die Opcode Darstellung für PUSH 00402123, wobei man hier aufgrund von little Endian eigentlich reinschreibt 232140, aber die 00 sowieso noch dort steht. Das "zwichenstück" @ ist Hex = 40 und wird in EAX reingeschrieben ab 402123. Im Code steht:
Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
0040212A  |.  83E0 BF       AND EAX,FFFFFFBF
Also nehmen wir @, weil 4 zu B komplementär ist und damit EAX = 00000000 ist.
Jetzt kommen aber meine Preisfragen ( :wink: ) :
Wie bist du auf die Adresse 402123 gekommen?
Wie berechnest du die Serial? Was rauskommen soll, weiß ich ja aufgrund des CRC vom Namen. "Einfach" rückwärts rechnen ?

Vielen Dank dir.
 
Ich hoffe es stört dich nicht, wenn ich dir antworte.
Jetzt kommen aber meine Preisfragen ( :wink: ) :
Wie bist du auf die Adresse 402123 gekommen?
Ich hatte die Adresse in einem Post erwähnt. Man hätte aber auch darauf kommen können, da nach der Benutzung des Exceptionhandlers der Stack zerschossen wird und nur an zwei Stellen die vorher gesicherten Werte von ESP und EBP in die Register zurückgeschrieben werden.
Wie berechnest du die Serial? Was rauskommen soll, weiß ich ja aufgrund des CRC vom Namen. "Einfach" rückwärts rechnen?
Ich habe neben CRC32 nur das ganz einfache BASE64 verwendet. Das ist eigentlich auch keine Verschlüsselung, sondern ermöglicht es Binärcode mit ASCII-Zeichen darzustellen. Dieser Algorithmus lässt sich in zwei Richtungen ausführen (ASCII->BIN / BIN->ASCII). Mit BASE64 werden z.B. auch Emailanhänge übertragen, da das SMTP-Protokoll nur für ASCII ausgelegt ist.
 
Zuletzt bearbeitet:
Ich hoffe es stört dich nicht, wenn ich dir antworte.

Nein natürlich nicht ;-).

Ich hatte die Adresse in einem Post erwähnt.
Stimmt hatte ich aber schon wieder vergessen :rolleyes:. Die Werte braucht man doch aber gar nicht mehr im Register oder hab ich jetzt was auf die schnelle übersehen? Also ohne den Tipp wäre ich da nicht drauf gekommen, wenn CRC = Hash, dann hätte ich nur noch die Exception "überlisten" müssen. Da hätte ich dann einfach selber Code eingefügt und wäre an diese Adresse gesprungen, dadurch wäre natürlich aber die von dir gesuchte Serial anders gewesen als meine.
 
Bei 32Bit x86 ist der Stack mit einem Stackpointer ESP (Zeiger auf Speicheradresse von Stack) und einen Basepointer EBP (alter Stackpointer) realisiert. Auf dem Stack werden die Rücksprungadressen der Unterfunktionen abgelegt und wenn sich nach einer Exception falsche Werte in den Registern befinden, dann landest du nach einem return mit Sicherheit nicht mehr da, wo du hergekommen bist.
 
Zurück
Oben