Eines schönen Tages begannen verschiedene Kanäle im
Telegramm , einen
Link zum Crackmaker von LK zu werfen.
Diejenigen, die die Aufgabe erfolgreich abgeschlossen haben, werden zu einem Interview eingeladen! . Nach so einer lauten Aussage fragte ich mich, wie schwierig das Gegenteil sein würde. Wie ich diese Aufgabe gelöst habe, kann man unter dem Schnitt nachlesen (viele Bilder).
Als ich zu Hause ankam, las ich die Aufgabe noch einmal sorgfältig durch, lud das Archiv herunter und begann zu schauen, was sich darin befand. Und drinnen war:

Wir starten x64dbg, sichern nach dem Auspacken, schauen, was tatsächlich drin ist:


Wir nehmen den Dateinamen aus den Befehlszeilenargumenten -> öffnen, lesen -> den ersten Schritt verschlüsseln -> den zweiten Schritt verschlüsseln -> in eine neue Datei schreiben.
Es ist einfach, es ist Zeit, sich mit Verschlüsselung zu befassen.
Beginnen wir mit stage1
Unter der Adresse 0x4033f4 gibt es eine Funktion, die ich crypt_64bit_up genannt habe (später werden Sie verstehen, warum). Sie wird von einer Schleife irgendwo innerhalb von stage1 aufgerufen

Und ein bisschen schiefes Dekompilierungsergebnis

Zuerst habe ich versucht, den gleichen Algorithmus in Python umzuschreiben, ihn mehrere Stunden lang beendet und es stellte sich heraus, dass get_dword und byteswap aus den Namen klar sein sollten.
def _add(x1, x2): return (x1+x2) & 0xFFFFFFFF def get_buf_val(t, buffer): t_0 = t & 0xFF t_1 = (t >> 8) & 0xFF t_2 = (t >> 16) & 0xFF t_3 = (t >> 24) & 0xFF res = _add(get_dword(buffer, t_0 + 0x312), (get_dword(buffer, t_1 + 0x212) ^ _add(get_dword(buffer, t_2+0x112), get_dword(buffer, t_3+0x12))))
Aber dann habe ich beschlossen, auf die Konstanten 0x12, 0x112, 0x212, 0x312 zu achten (ohne Hex 18, 274, 536 ... nicht sehr ähnlich zu etwas Ungewöhnlichem). Wir versuchen, sie zu googeln und ein ganzes Repository (Hinweis: NTR) mit der Implementierung von Verschlüsselungs- und
Entschlüsselungsfunktionen zu finden. Das ist viel Glück. Wir versuchen, eine Testdatei mit zufälligem Inhalt im Originalprogramm zu verschlüsseln, sie zu sichern und dieselbe Datei mit einem kleinen Skript zu verschlüsseln. Alles sollte funktionieren und die Ergebnisse sollten gleich sein. Danach versuchen wir es zu entschlüsseln (ich habe beschlossen, nicht auf Details einzugehen und einfach die Entschlüsselungsfunktion aus der Quelle zu kopieren und einzufügen)
def crypt_64bit_down(initials, keybuf): x = initials[0] y = initials[1] for i in range(0x11, 1, -1): z = get_dword(keybuf, i) ^ x x = get_buf_val(z, keybuf) x = y ^ x y = z res_0 = x ^ get_dword(keybuf, 0x01)
Wichtiger Hinweis: Der Schlüssel im Repository unterscheidet sich vom Schlüssel im Programm (was ziemlich logisch ist). Nachdem der Schlüssel initialisiert wurde, habe ich ihn einfach in eine Datei geschrieben. Dies ist buffer / keybuf
Wir gehen zum zweiten Teil über
Hier ist alles viel einfacher: Zuerst wird ein Array eindeutiger Zeichen mit einer Größe von 0 x 55 Byte im Bereich (33, 118) (druckbare Zeichen) erstellt, dann wird der 32-Bit-Wert aus dem zuvor erstellten Array in 5 druckbare Zeichen gepackt.


Da es beim Erstellen des oben genannten Arrays keine Zufälligkeit gibt, ist dieses Array jedes Mal, wenn das Programm gestartet wird, dasselbe. Wir sichern es nach der Initialisierung und können stage_2 mit einer einfachen Funktion entpacken
def stage2_unpack(packed_data, state):
Wir machen so etwas:
f = open('stage1.state.bin', 'rb') stage1 = f.read() f.close() f = open('stage2.state.bin', 'rb') stage2 = f.read() f.close() f = open('rprotected.dat', 'rb') packed = f.read() f.close() unpacked_from_2 = stage2_unpack(packed, stage2) f = open('unpacked_from_2', 'wb') f.write(unpacked_from_2) f.close() unpacked_from_1 = stage1_unpack(unpacked_from_2, stage1) f = open('unpacked_from_1', 'wb') f.write(unpacked_from_1) f.close()
Und wir bekommen das Ergebnis
