[ ENTREES ]
I.1- Name :
La recherche de l'api GetDlgItemTextA
nous mene ici :
_text:00402FD7 GetName:
_text:00402FD7
push 63h
; nMaxCount
_text:00402FD9
push offset Name ; lpString
_text:00402FDE
push 0C8h
; nIDDlgItem
_text:00402FE3
push [ebp+hDlg] ; hDlg
_text:00402FE6
call GetDlgItemTextA
_text:00402FEB
mov ds:SerialSize, eax
_text:00402FF0
cmp ds:SerialSize, 0
_text:00402FF7
jnz short GetSerial
_text:00402FF9
push offset aEnterName ; lpString
_text:00402FFE
push 0C9h
; nIDDlgItem
_text:00403003
push [ebp+hDlg]
; hDlg
_text:00403006
call SetDlgItemTextA
_text:0040300B
jmp EndCheckSerial
Donc le "Name" entrée par l'utilisateur doit etre composé
d'au moins un caractére... ;p
I.2- Serial :
_text:00403038 GetSerial:
_text:00403038
push 23h
; nMaxCount
_text:0040303A
push offset Serial ; lpString
_text:0040303F
push 0C9h
; nIDDlgItem
_text:00403044
push [ebp+hDlg] ; hDlg
_text:00403047
call GetDlgItemTextA
_text:0040304C
mov ds:SerialSize, eax
_text:00403051
cmp ds:SerialSize, 20h
_text:00403058
jnb short Next
_text:0040305A
push offset aMaybeAskJoe? ; lpString
_text:0040305F
push 0C9h
; nIDDlgItem
_text:00403064
push [ebp+hDlg] ; hDlg
_text:00403067
call SetDlgItemTextA
_text:0040306C
jmp EndCheckSerial
Puis on recupere le Serial ( qui doit etre composé de 32
caracteres )...
_text:00403071 Next:
_text:00403071
mov ds:FlagValidCar, 0
_text:0040307B
mov ds:CurrentCar, 0
_text:00403085
jmp short O9AF
_text:00403087 ; ---------------------------------------------------------------------------
_text:00403087
_text:00403087 LoopO9AF:
_text:00403087
mov edx, ds:CurrentCar
_text:0040308D
movzx edi, Serial[edx]
_text:00403095
cmp edi, 30h
_text:00403098
jge short loc_0_4030A4
_text:0040309A
mov ds:FlagValidCar, 1
_text:004030A4
_text:004030A4 loc_0_4030A4:
_text:004030A4
mov edx, ds:CurrentCar
_text:004030AA
movzx edi, Serial[edx]
_text:004030B2
cmp edi, 39h
_text:004030B5
jle short loc_0_4030F1
_text:004030B7
mov edx, ds:CurrentCar
_text:004030BD
movzx edi, Serial[edx]
_text:004030C5
cmp edi, 46h
_text:004030C8
jle short loc_0_4030D4
_text:004030CA
mov ds:FlagValidCar, 1
_text:004030D4
_text:004030D4 loc_0_4030D4:
_text:004030D4
mov edx, ds:CurrentCar
_text:004030DA
movzx edi, Serial[edx]
_text:004030E2
cmp edi, 41h
_text:004030E5
jge short loc_0_4030F1
_text:004030E7
mov ds:FlagValidCar, 1
_text:004030F1
_text:004030F1 loc_0_4030F1:
_text:004030F1
inc ds:CurrentCar
_text:004030F7
_text:004030F7 O9AF:
_text:004030F7
mov edi, ds:SerialSize
_text:004030FD
cmp ds:CurrentCar, edi
_text:00403103
jb short LoopO9AF
_text:00403105
cmp ds:FlagValidCar, 0
_text:0040310C
jnz short ErrorSerialCar
On verifie ensuite que le serial ne comporte que des
caracteres appartenant à [0-9A-F]...
_text:0040310E
push offset Serial
_text:00403113
call ascii2hex
_text:00403118
add esp, 4
Puis on le convertit en une valeur hexadecimal ( ie '0' => 00h,
..., '9' => 09h, 'A' => 0Ah, ... ,'F' => 0Fh )
_text:00403120
push ds:SerialSize
_text:00403126
push offset Serial
_text:0040312B
push offset Name
_text:00403130
call CheckSerial
_text:00403135
add esp, 0Ch
_text:00403138
cmp eax, 0
_text:0040313B
jz short BadSerial
Puis on verifie la validité du serial....
[ ANALYSE ]
II.1- Square
La routine SquareCipher utilise 5 tables dont les valeurs correspondent
à celles utilisées par : Square
Quelques recherches sur Square nous permettent de deduire le role de
certains procedure:
-squareGenerateRoundKeys (key, roundKeys_e, roundKeys_d);
-squareEncrypt (word32 text[4], roundKeys_e);
_text:00402F0A
push ebp
_text:00402F0B
mov ebp, esp
_text:00402F0D
sub esp, 168h
_text:00402F13
push esi
_text:00402F14
push edi
_text:00402F15
lea edi, [ebp+lpPhrase]
_text:00402F18
lea esi, [ keyword ]
_text:00402F1E
mov ecx, 47h
_text:00402F23
repe movsb
_text:00402F25
lea edi, [ebp+RoundKey_d]
_text:00402F2B
push edi
_text:00402F2C
lea edi, [ebp+RoundKey_e]
_text:00402F32
push edi
_text:00402F33
lea edi, [ebp+lpPhrase]
_text:00402F36
push edi
_text:00402F37
call GenerateRoundKeys_e
_text:00402F3C
add esp, 0Ch
_text:00402F3F
lea edi, [ebp+RoundKey_e]
_text:00402F45
push edi
_text:00402F46
push [ebp+Serial_hex]
_text:00402F49
call squareEncrypt
_text:00402F4E
add esp, 8
On se retrouve donc avec 4 dword correspondant au chiffrement de Serial_hex
par Square ( avec keyword pour mot clef ;))
squareGenerateRoundKeys (keyword, roundKeys_e, roundKeys_d);
Serial_hex := squareEncrypt (Serial_hex,
roundKeys_e);
II.2- Magic
Puis on effectue une transformation sur chacun des 4 dword obtenus:
_text:00403250
mov ecx, 4
_text:00403255
mov ebx, 4078BCh
_text:0040325A
mov esi, [ebp+Serial_hex]
_text:0040325D
mov edi, esi
_text:0040325F
_text:0040325F LoopC:
_text:0040325F
lodsd
_text:00403260
push eax
_text:00403261
add ebx, 80h
_text:00403267
push ebx
_text:00403268
call LinearMat
_text:0040326D
add esp, 8
_text:00403270
stosd
_text:00403271
loop LoopC
C'est a dire :
Serial_hex[0] := LinearMat(Serial_hex[0],Mat[0])
Serial_hex[1] := LinearMat(Serial_hex[1],Mat[1])
Serial_hex[2] := LinearMat(Serial_hex[2],Mat[2])
Serial_hex[3] := LinearMat(Serial_hex[3],Mat[3])
II.3- "MD5"
D'apres PEiD cette routine est un hash MD5 cependant plusieurs modifications
ont ete apportés ( initialisation, utilisation de tables...)
_text:00403233
push offset Buffer
_text:00403238
call Ini
_text:0040323D
add esp, 4
_text:00403240
push offset Buffer
_text:00403245
push [ebp+Name]
_text:00403248
call Hash
Quoiqu'il en soit on se retrouve avec un hash ( de 4 dword ) du Name
dans [Buffer]...
[Buffer] := modified_MD5[Buffer];
II.4- CPUiD
_text:00403273
mov esi, offset Buffer
_text:00403278
xor eax, eax
_text:0040327A
cpuid
_text:0040327C
xor [esi], ebx
_text:0040327E
rol ebx, 0Bh
_text:00403281
xor [esi+4], ebx
_text:00403284
rol ebx, 0Bh
_text:00403287
xor [esi+8], ebx
_text:0040328A
rol ebx, 11h
_text:0040328D
xor [esi+0Ch], ebx
Finalement on applique un xor de la valeur renvoyée par cpuid
sur la valeur contenue dans [Buffer]
[Buffer + 0] := [Buffer + 0] xor cpuid;
[Buffer + 1] := [Buffer + 1] xor cpuid;
[Buffer + 2] := [Buffer + 2] xor cpuid;
[Buffer + 3] := [Buffer + 3] xor cpuid;
II.5- Final Cmp
_text:00403273
mov esi, offset Buffer
[ .................................................. ]
text:00403290
xor eax, eax
_text:00403292
mov edi, [ebp+Serial_hex]
_text:00403295
mov ecx, 5
_text:0040329A
repe cmpsd
Et pour terminer on compare la valeur contenue dans [Buffer] à
celle contenue dans [Serial_hex]
[ KEYGEN ]
Pour resumer:
squareGenerateRoundKeys (keyword, roundKeys_e, roundKeys_d);
Serial_hex := squareEncrypt (Serial_hex,
roundKeys_e);
Serial_hex[0] := LinearMat(Serial_hex[0],Mat[0]);
Serial_hex[1] := LinearMat(Serial_hex[1],Mat[1]);
Serial_hex[2] := LinearMat(Serial_hex[2],Mat[2]);
Serial_hex[3] := LinearMat(Serial_hex[3],Mat[3]);
[Buffer] := modified_MD5[Buffer];
Buffer[0] := Buffer[0] xor cpuid;
Buffer[1] := Buffer[1] xor cpuid;
Buffer[2] := Buffer[2] xor cpuid;
Buffer[3] := Buffer[3] xor cpuid;
[Buffer] ?= [Serial_hex]
L'algo du keygen correspondant est donc:
[Buffer] := modified_MD5[Buffer];
[Buffer + 0] := [Buffer + 0] xor cpuid;
[Buffer + 1] := [Buffer + 1] xor cpuid;
[Buffer + 2] := [Buffer + 2] xor cpuid;
[Buffer + 3] := [Buffer + 3] xor cpuid;
Buffer[0] := LinearMat(Buffer[0],Matt[0]);
Buffer[1] := LinearMat(Buffer[1],Matt[1]);
Buffer[2] := LinearMat(Buffer[2],Matt[2]);
Buffer[3] := LinearMat(Buffer[3],Matt[3]);
squareGenerateRoundKeys (keyword, roundKeys_e, roundKeys_d);
Serial_hex := squareDecrypt (Buffer, roundKeys_d);
La partie MD5 et cpuid ne pose pas vraiment de probleme...
III.1 - LinearMat
Un petit detour par LinearMat:
_text:004032A7 LinearMat proc
near
_text:004032A7
_text:004032A7 lpMat
= dword ptr 10h
_text:004032A7 lpDD
= dword ptr 14h
_text:004032A7
_text:004032A7
push ecx
_text:004032A8
push esi
_text:004032A9
push ebp
_text:004032AA
mov esi, [esp+lpMat]
_text:004032AE
mov eax, [esp+lpDD]
_text:004032B2
or ebp, 0FFFFFFFFh
_text:004032B5
mov ecx, 20h
_text:004032BA
xor edx, edx
_text:004032BC
test eax, eax
_text:004032BE
jnz short ForEachBit
_text:004032C0
xor eax, eax
_text:004032C2
jmp short end_LinearMat
_text:004032C4 ; ---------------------------------------------------------------------------
_text:004032C4
_text:004032C4 ForEachBit:
_text:004032C4
inc ebp
_text:004032C5
test eax, 1
_text:004032CA
jz short DontAdd
_text:004032CC
xor edx, [esi+ebp*4]
_text:004032CF
_text:004032CF DontAdd:
_text:004032CF
shr eax, 1
_text:004032D1
loop ForEachBit
_text:004032D3
xchg eax, edx
_text:004032D4
_text:004032D4 end_LinearMat:
_text:004032D4
pop ebp
_text:004032D5
pop esi
_text:004032D6
pop ecx
_text:004032D7
retn
_text:004032D7 LinearMat endp
Il y a plusieurs facon d'interpreter cette partie du code... Je pense
que la plus simple est de la considerer comme une application lineaire
de GF(2^32) dans GF(2^32) ( le xor est alors consideré comme un
+ ) :
LinearMat(DD) = LinearMat(DD and 2^0) + ... + LinearMat(DD and 2^31)
= DD'
...et le tableau [lpMat] = Mat comme la matrice de l'endomorphisme...
donc pour pouvoir passer de DD' à DD il suffit
de trouver la matrice Mat-1 telle que:
Mat * Mat-1 = I32
On obtiendra alors: LinearMat-1(DD') = DD
Comment trouver Mat-1 ?
En construisant la matrice T = ( I32 | Mat ) et en lui appliquant
l'agorithme de Gauss-Jourdan ( tres simple dans Z/2Z ;p)
on obtient T = ( Mat-1 | I32 ).... on a
plus qu'a recuperer Mat-1 et le tour est joué...
III.2- SquareDecrypt
Pour cette partie il suffit de recuperer roundKeys_d
et d'utiliser "squareDecrypt"... en l'implementant ? :)
En observant un peu le code on s'apercoit que certaines parties ne sont
jamais executées (aucun call/jmp permettant d'y acceder )
_text:004022BA
push ebp
_text:004022BB
mov ebp, esp
_text:004022BD
sub esp, 10h
_text:004022C0
push ebx
_text:004022C1
push esi
_text:004022C2
push edi
_text:004022C3
mov edi, [ebp+8]
_text:004022C6
mov esi, [ebp+0Ch]
_text:004022C9
mov esi, ds:0[esi]
_text:004022D0
xor ds:0[edi], esi
_text:004022D7
mov edi, [ebp+8]
_text:004022DA
add edi, 4
[...................................................]
_text:00402E7E
movzx ebx, Sd[ebx]
_text:00402E86
shl ebx, 10h
_text:00402E89
xor esi, ebx
_text:00402E8B
mov ebx, [ebp-4]
_text:00402E8E
shr ebx, 18h
_text:00402E91
and ebx, 0FFh
_text:00402E97
movzx ebx, Sd[ebx]
_text:00402E9F
shl ebx, 18h
_text:00402EA2
xor esi, ebx
_text:00402EA4
mov ebx, [ebp+0Ch]
_text:00402EA7
xor esi, [ebx+8Ch]
_text:00402EAD
mov [edi+0Ch], esi
_text:00402EB0
pop edi
_text:00402EB1
pop esi
_text:00402EB2
pop ebx
_text:00402EB3
leave
_text:00402EB4
retn
Plus etrange encore, cette partie du code fait reference a 5 tableaux
dont les valeurs correspondent a celles normalement utilisées par
la procedure squareDecrypt... et effectivement cette portion du
code est la procedure squareDecrypt :p
[ END ]
Il suffit de tout rassembler et on obtient un joli keygen... au
detail pres que le CrackMe contient un bug et qu'il faut donc le relancer
entre chaque test de serial... ;)
Name |
Amenesia |
Serial |
D929B716E5C044B00D6714E25549D914 |
Si vous trouvez une erreur ou avez une question : tchernozium@yahoo.fr
|