Mettre en echec le Crackme1 de Spud... [zip]
(Identifier et casser un serial "crypté" par XOR)

Nous allons aujourd'hui nous attacher à cracker le crackme n°1 de Spud.
Ce crackme a l'avantage de sortir un peu de l'ordinaire.

Présentation sommaire :
- un seul champ à renseigner (serial unique ?)
- si le serial est mauvais on quitte direct (radical!)
- petit éxecutable de 4ko non protegé.

Bon, le code est si petit que je n'ai pas besoin de vous dire comment arriver ici :
(Hmemcpy ou GetDlgItemTextA feront très bien l'affaire)

(IMPORTANT : NDOracle:
Pour des raisons de lisibilité, les commentaires sont en Arial gras et entre parenthèse.
Chaque commentaire concerne la ligne qui le précède.
La partie jaune du code est une boucle. La partie bleue du code ne sert à rien! La partie rouge ... bah vous verrez ! :-)
Voilà c'est tout merci.)

:00401057 E81C010000 Call 00401178
:0040105C 0BC0 or eax, eax
:0040105E 0F84A7000000 je 0040110B
:00401064 60 pushad
:00401065 33F6 xor esi, esi
:00401067 33FF xor edi, edi
:00401069 B908000000 mov ecx, 00000008
:0040106E 683C304000 push 0040303C
(Adresse de notre serial, en faisant 'd 40303c' on peut voir l'évolution du serial.)
:00401073 5E pop esi
:00401074 8BD6 mov edx, esi
:00401076 80362C xor byte ptr [esi],
On prend chaque caractère du serial, et on le xor par 2C (1ere constatation le serial fait 8 caractères).
:00401079 46 inc esi
:0040107A E2FA loop 00401076

:0040107C 8BF2 mov esi, edx
:0040107E 8A06 mov al, byte ptr [esi]
(1er caractère)

:00401080 8A5E07 mov bl, byte ptr [esi+07]
(8ème caractère)

:00401083 32C3 xor al, bl
((1)Et on xor le 1er caractère avec le 8eme caractère)

:00401085 8802 mov byte ptr [edx], al
(en 40303C on remplace la valeur existante par la valeur obtenue (idem pour la suite ...))
:00401087 8A4601 mov al, byte ptr [esi+01]
(2ème caractère)
:0040108A 8A5E06 mov bl, byte ptr [esi+06]
(7ème caractère)
:0040108D 32C3 xor al, bl
((2) 2ème caractère xor 7ème caractère)

:0040108F 884201 mov byte ptr [edx+01], al
(modif du 2ème caractère)
:00401092 8A4602 mov al, byte ptr [esi+02]
(3ème caractère)
:00401095 8A5E05 mov bl, byte ptr [esi+05]
(6ème caractère)
:00401098 32C3 xor al, bl
((3) 3ème caractère xor 6ème caractère)

:0040109A 884202 mov byte ptr [edx+02], al
(modif du 3ème caractère)
:0040109D 8A4603 mov al, byte ptr [esi+03]
(4ème caractère)
:004010A0 8A5E04 mov bl, byte ptr [esi+04]
(5ème caractère)
:004010A3 32C3 xor al, bl
((4) 4ème caractère xor 5ème caractère)

:004010A5 884203 mov byte ptr [edx+03], al
(modif du 4ème caractère) 
:004010A8 8BF2 mov esi, edx

(La partie ci-dessous en bleue ne sert à rien... Peut être pour nous embrouiller?)
:004010AA 8A06 mov al, byte ptr [esi]
:004010AC 8A5E02 mov bl, byte ptr [esi+02]
:004010AF 32C3 xor al, bl
:004010B1 8A5E01 mov bl, byte ptr [esi+01]
:004010B4 8A4E03 mov cl, byte ptr [esi+03]
:004010B7 32D9 xor bl, cl
:004010B9 32C3 xor al, bl
:004010BB 5E pop esi
:004010BC B908000000 mov ecx, 00000008
:004010C1 3006 xor byte ptr [esi], al
:004010C3 46 inc esi
:004010C4 E2FB loop 004010C1

:004010C6 B908000000 mov ecx, 00000008
:004010CB 8BF2 mov esi, edx
:004010CD 83C608 add esi, 00000008
:004010D0 8BFE mov edi, esi
:004010D2 83EE08 sub esi, 00000008
:004010D5 B8241F1C48 mov eax, 481C1F24
:004010DA 8907 mov dword ptr [edi], eax
:004010DC B844434049 mov eax, 49404344
:004010E1 894704 mov dword ptr [edi+04], eax
:004010E4 8A06 mov al, byte ptr [esi]
:004010E6 8A1F mov bl, byte ptr [edi]
:004010E8 38D8 cmp al, bl
:004010EA 7517 jne 00401103
:004010EC 46 inc esi
:004010ED 47 inc edi
:004010EE E2F4 loop 004010E4
:004010F0 6A00 push 00000000

* Possible StringData Ref from Data Obj ->"CRACKED" => bingo
|
:004010F2 682D304000 push 0040302D

* Possible StringData Ref from Data Obj ->"Crackme crack"
|
:004010F7 681A304000 push 0040301A
:004010FC 6A00 push 00000000

* Reference To: USER32.MessageBoxA, Ord:01BBh
|
:004010FE E86F000000 Call 00401172

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004010EA(C)
|
:00401103 6A00 push 00000000

* Reference To: KERNEL32.ExitProcess, Ord:0075h (=> bye bye...)
|
:00401105 E856000000 Call 00401160
:0040110A 61 popad

A la fin, notre serial doit être égal à ca :

:004010D5 B8241F1C48 mov eax, 481C1F24
:004010DA 8907 mov dword ptr [edi], eax
:004010DC B844434049 mov eax, 49404344
:004010E1 894704 mov dword ptr [edi+04], eax
(EDI = 241F1C4844434049)
:004010E4 8A06 mov al, byte ptr [esi]
:004010E6 8A1F mov bl, byte ptr [edi]
:004010E8 38D8 cmp al, bl
(Comparaison entre ESI (notre serial) et EDI)

Donc ce qu'il faut obtenir au terme des différentes transformations c'est une chaîne égale à :

On va d'abord s'attacher à trouver la partie la plus facile du serial :

Il s'agit des 4 derniers caractères, en effet ils ne subissent qu'une seule transformation.

Donc il nous faut trouver ceci :

5ème caractère Xor 2C = 44 (valeur héxa évidemment)
6ème caractère Xor 2C = 43
7ème caractère Xor 2C = 40
8ème caractère Xor 2C = 49


Pour cela, il y a deux méthodes :

Méthode 1) On est malin (bon c'est quoi l'autre solution ?)
Tout d'abord un petit rappel, je me permets de citer un passage du texte : 'Cryptosysteme - XOR Par Sabrina'

"Avant, d'être considéré comme une méthode de cryptage, le XOR est avant tout une opération logique. En effet, le XOR est un opérateur binaire qui possède 2 opérandes et qui renvoie 1 résultat. Le XOR se manipule bit à bit de la façon suivante:

1 XOR 1 = 0
1 XOR 0 = 1
0 XOR 1 = 1
0 XOR 0 = 0
[...]

CASSER LE XOR
Il faut bien voir que la donnée de C (clé) permet de retrouver entièrement M (message initial en clair). Toute la sécurité du XOR réside donc dans la possession de la clé C. Ainsi, on cherchera avant tout à déterminer la clé."

Fin de citation.

Ici, nous on va un petit peu adapter, car en effet, ici on connait C (la clé) il s'agit de 2C.
Si Caractère Crypté = Caractère initial Xor Clé
Alors Caractère Crypté Xor Clé = Caractère initial (ce qui nous intéresse en l'occurrence)

Ainsi :
Si 5ème caractère Xor 2C = 44 il faut faire : 44 Xor 2C = 68
Si 6ème caractère Xor 2C = 43 il faut faire : 43 Xor 2C = 6F
Si 7ème caractère Xor 2C = 40 il faut faire : 40 Xor 2C = 6C
Si 8ème caractère Xor 2C = 49 il faut faire : 49 Xor 2C = 65
NB : utilisez la calculatrice windows en mode scientifique et utilisez la fonction Xor.

Méthode 2) On est plutôt bourrin

On peut se créer un p'tit programme en VB par exemple (Oui je sais je vais encore me faire huer) qui pourrait ressembler à ça :

Private Sub Command1_Click()

X = 0
begin:
A = X Xor 44
'44d = 2C en héxa
If A = 68 Then
'68d = 44h

MsgBox Hex((A)) & " soit " & Chr(X)
'donne la valeur en héxa et le caractère correspondant
Else
X = X + 1
GoTo begin

End If
End Sub

Evidemment, ici il faut à modifier à chaque fois les valeurs à trouver. Par exemple, pour trouver le 6ème caractère, il faudrait modifier cette ligne :
If A = 68 Then ==>> If A = 67 then '67d = 43h

Bref, quelque que soit la manière retenue nous avons à présent les 4 derniers caractères du serial ce qui nous donne en héxa 686F6C65. Ce qui en ASCII nous donne : 'hole'

Maintenant, on peut s'attaquer à trouver les valeurs des 4 premiers caractères.
On connait les valeurs de [ESI+04] à [ESI+07]

Pour trouver valeurs manquantes, il nous faut résoudre ceci :

[ESI] Xor 44 = 24 (en effet, 44 correspond à ESI+04)
[ESI] Xor 43 = 1F ( " 43 " " ESI+05)
[ESI] Xor 40 = 1C ( " 40 " " ESI+06)
[ESI] Xor 49 = 48 ( " 49 " " ESI+07)


Si (1er caractère Xor 2C) Xor 49 = 24 il faut faire ceci : (49 Xor 2C) Xor 24 = 41
Si (2ème caractère Xor 2C) Xor 40 = 1F " " (40 Xor 2C) Xor 1F = 73
Si (3ème caractère Xor 2C) Xor 43 = 1C " " (43 Xor 2C) Xor 1C = 73
Si (4ème caractère Xor 2C) Xor 44 = 48 " " (44 Xor 2C) Xor 48 = 20

Ainsi les 4 premiers caractères sont 41737320 en héxa, ce qui en ASCII nous donne : 'Ass ' [on peut ici évidemment refaire un ptit programme en VB ou autre pour retrouver ces mêmes valeurs avec la méthode force brute]

Au final le serial est : Ass hole
On teste ... et Crackme cracké, Bingo ;)

Voili, Voilou, en espérant avoir été compréhensible.