Analyse du code:
Visiblement le code est brouillé mais la methode utilisée
n'a rien de bien compliquée :
FHCF:0041508C start
proc near
FHCF:0041508C
nop
FHCF:0041508D
nop
FHCF:0041508E
nop
FHCF:0041508F
nop
FHCF:00415090
push eax
FHCF:00415091
push edx
FHCF:00415092
push esi
FHCF:00415093
push edi
FHCF:00415094
mov edi, 401000
; adresse de debut
FHCF:00415099
mov esi, 0AFFFh
; longueur
FHCF:0041509E
mov dl, 5Ah
; valeur du xor
FHCF:004150A0
call Decode
FHCF:004150A5
mov edi, 0040D000 ; adresse
de debut
FHCF:004150AA
mov esi, 1FFFh
; longueur
FHCF:004150AF
mov dl, 5Ah
; valeur du xor
FHCF:004150B1
call Decode
FHCF:004150B6
mov edi, 0040C600 ; adresse de
debut
FHCF:004150BB
mov esi, 2B0h
; longueur
FHCF:004150C0
mov dl, 0
FHCF:004150C2
call EffaceNomAPI
FHCF:004150C7
pop edi
FHCF:004150C8
pop esi
FHCF:004150C9
pop edx
FHCF:004150CA
pop eax
FHCF:004150CB
push 407952
; OEP
FHCF:004150D0
retn
FHCF:004150D0 start
endp
FHCF:004150D0
FHCF:004150D1
FHCF:004150D1 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
FHCF:004150D1 Decode
proc near
FHCF:004150D1
FHCF:004150D1
ror dl, 1
FHCF:004150D3
ror dl, 1
FHCF:004150D5
ror dl, 1
FHCF:004150D7
ror dl, 1
FHCF:004150D9
inc dl
FHCF:004150DB
mov dh, [edi]
FHCF:004150DD
xor dh, dl
FHCF:004150DF
mov [edi], dh
FHCF:004150E1
dec esi
FHCF:004150E2
inc edi
FHCF:004150E3
test esi, esi
FHCF:004150E5
jnz short sub_0_4150D1
FHCF:004150E7
retn
FHCF:004150E7 Decode
endp
FHCF:004150E7
FHCF:004150E8
FHCF:004150E8 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
FHCF:004150E8 EffaceNomAPI proc near
FHCF:004150E8
FHCF:004150E8
mov [edi], dh
FHCF:004150EA
dec esi
FHCF:004150EB
inc edi
FHCF:004150EC
test esi, esi
FHCF:004150EE
jnz short sub_0_4150E8
FHCF:004150F0
retn
FHCF:004150F0 EffaceNomAPI endp
Donc on remplace le "mov edi, 0040C600" ( apres le
decodage et avant l'effacement de la table d'import) par un jmp $, dump,
puis reconstruction de l'IAT et retablissement de l'OEP...
Presence des valeurs caracteristiques des fonctions de hash ; SHA-1,
MD5 , Ripe-MD ( ie 67453201h, 0EFCDAB89h, 98BADCFEh, 10325476h )
_text:004012DE
lea eax, [ebp-22Ch]
_text:004012E4
push eax
_text:004012E5
call IniHash
Effectivement quelques lignes plus bas une chaine est construite, puis
hashée :
x |
x |
x |
l |
l |
F |
H |
C |
F |
- |
Y |
E |
A |
H |
! |
! |
|
| |
| |
| |
\ |
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
| |
| |
|
| |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
longueur du serial (en decimal ) |
| |
| |
| |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
21éme caractere du serial |
| |
| |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
14éme caractere du serial |
| |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
_ |
7éme caractere du serial |
_text:004012ED
mov cl, [Serial+6]
_text:004012F3
mov [Buffer], cl
_text:004012F9
mov dl, [Serial+13]
_text:004012FF
mov [Buffer+1], dl
_text:00401305
mov al, [Serial+20]
_text:0040130A
mov [Buffer+2], al
_text:0040130F
mov [ebp+adr], offset [Buffer+3]
_text:00401316
mov ecx, [ebp-104h]
; Taille du Serial
_text:0040131C
push ecx
_text:0040131D
push offset aD
; "%d"
_text:00401322
mov edx, [ebp+adr]
_text:00401325
push edx
_text:00401326
call _sprintf
Le programme convertit la valeur obtenu lors du hash ( MD5 ) au format
Miracl...
_text:004013B7
mov edx, [ebp+adrHashMcl]
_text:004013BD
push edx
_text:004013BE
lea eax, [ebp+Hash]
_text:004013C4
push eax
_text:004013C5
push 10h
_text:004013C7
call CvrtMiracl
...crée le nombre de valeur "Bn6EN1dDFrupNxw1Wk4WO5==" (en base
64)
ie 67E8437574316BBA9371C355A4E163B9h...
_text:004013CF
push offset aBn6en1ddfrupnxw1wk4wo5
_text:004013D4
mov ecx, [ebp+adrHashKey]
_text:004013DA
push ecx
_text:004013DB
call CreatMiracl
et compare les 2 valeurs:
_text:004013E0
add esp, 8
_text:004013E3
mov edx, [ebp+adrHashMcl]
_text:004013E9
push edx
_text:004013EA
mov eax, [ebp+adrHashKey]
_text:004013F0
push eax
_text:004013F1
call _compare
_text:004013F6
add esp, 8
_text:004013F9
test eax, eax
_text:004013FB
jz Suite
Autrement dit, pour etre valide le hash de la chaine doit etre egal
à 67E8437574316BBA9371C355A4E163B9h. La seule methode pour determiner
la chaine à partir de la valeur du hash est de tenter un brute force
(vu que l'incertitude ne porte que sur 5 caracteres cela reste raisonnable
).
Apres quelques secondes, on obtient : "---27FHCF-YEAH!!"
Une fois que que le hash a ete verifié les "-" sont retirés
du serial
_text:00401439 DecoupPartSerial:
_text:00401439
mov ecx, [ebp+tailleSerial]
_text:0040143F
add ecx, 1
_text:00401442
mov [ebp+tailleSerial], ecx
_text:00401448
_text:00401448 loc_0_401448:
_text:00401448
mov edi, offset Serial
_text:0040144D
or ecx, 0FFFFFFFFh
_text:00401450
xor eax, eax
_text:00401452
repne scasb
_text:00401454
not ecx
_text:00401456
add ecx, 0FFFFFFFFh
_text:00401459
cmp [ebp+tailleSerial], ecx ;
longueur Serial
_text:0040145F
jge short FinREcupVal
_text:00401461
cmp [ebp+tailleSerial], 6
_text:00401468
jnz short Part2
_text:0040146A
mov edx, [ebp+tailleSerial]
_text:00401470
add edx, 1
_text:00401473
mov [ebp+tailleSerial], edx
_text:00401479
_text:00401479 Part2:
_text:00401479
cmp [ebp+tailleSerial], 0Dh
_text:00401480
jnz short Part3
_text:00401482
mov eax, [ebp+tailleSerial]
_text:00401488
add eax, 1
_text:0040148B
mov [ebp+tailleSerial], eax
_text:00401491
_text:00401491 Part3:
_text:00401491
cmp [ebp+tailleSerial], 14h
_text:00401498
jnz short REcupVAl
_text:0040149A
mov ecx, [ebp+tailleSerial]
_text:004014A0
add ecx, 1
_text:004014A3
mov [ebp+tailleSerial], ecx
_text:004014A9
_text:004014A9 REcupVAl:
_text:004014A9
mov edx, [ebp+var_108]
_text:004014AF
mov eax, [ebp+tailleSerial]
_text:004014B5
mov cl, [Serial+eax]
_text:004014BB
mov [Buffer+edx], cl
_text:004014C1
mov edx, [ebp+var_108]
_text:004014C7
add edx, 1
_text:004014CA
mov [ebp+var_108], edx
_text:004014D0
jmp DecoupPartSerial
_text:004014D5 ; ---------------------------------------------------------
_text:004014D5
_text:004014D5 FinREcupVal:
Puis on s'assure que le serial n'est composé que de chiffre et
des lettres A B C D E F...
_text:004014E1 FiltreCar:
_text:004014E1
mov eax, [ebp+tailleSerial]
_text:004014E7
add eax, 1
_text:004014EA
mov [ebp+tailleSerial], eax
_text:004014F0
_text:004014F0 carA_F:
_text:004014F0
mov edi, offset Buffer
_text:004014F5
or ecx, 0FFFFFFFFh
_text:004014F8
xor eax, eax
_text:004014FA
repne scasb
_text:004014FC
not ecx
_text:004014FE
add ecx, 0FFFFFFFFh
_text:00401501
cmp [ebp+tailleSerial], ecx ; longueurSerial
_text:00401507
jge short FinCheckFormat
_text:00401509
mov ecx, [ebp+tailleSerial]
_text:0040150F
movsx edx, [Buffer+ecx]
_text:00401516
cmp edx, 41h
_text:00401519
jl short Chiffre
_text:0040151B
mov eax, [ebp+tailleSerial]
_text:00401521
movsx ecx, [Buffer+eax]
_text:00401528
cmp ecx, 46h
_text:0040152B
jle SuiteFiltreCar
_text:0040152D
_text:0040152D Chiffre:
_text:0040152D
mov edx, [ebp+tailleSerial]
_text:00401533
movsx eax, [Buffer+edx]
_text:0040153A
cmp eax, 30h
_text:0040153D
jl ErreurFormat
_text:0040153F
mov ecx, [ebp+tailleSerial]
_text:00401545
movsx edx, [Buffer+ecx]
_text:0040154C
cmp edx, 39h
_text:0040154F
jle SuiteFiltreCar
_text:00401551
_text:00401551 ErreurFormat:
_text:00401577 ; -----------------------------------------------------------
_text:00401577
_text:00401577 SuiteFiltreCar:
_text:00401577
jmp FiltreCar
_text:0040157C ; -----------------------------------------------------------
_text:0040157C
_text:0040157C FinCheckFormat:
Et finallement les 12 premiers caracteres sont utilisés pour
creer un nom au format Miracl et les 12 dernieres pour en creer un autre...
_text:00401582
mov dword ptr [eax+220h], 10h
; base
_text:0040158C
mov [ebp+Part2serial], offset Buffer_12
_text:00401593
mov ecx, [ebp+PArt2serial]
_text:00401596
push ecx
_text:00401597
mov edx, [ebp+Part2SerialMcl]
_text:0040159D
push edx
_text:0040159E
call CreatMiracl
_text:004015A6
mov [Buffer+12], 0
_text:004015AD
push offset Buffer
_text:004015B2
mov eax, [ebp+Part1SerialMcl]
_text:004015B8
push eax
_text:004015B9
call CreatMiracl
On arrive enfin à la verification du serial. ( sachant des le
depart que ce keygenme repose sur le DSA l'analyse du code en est facilitée
)
Signature DSA en quelques lignes:
Parametres:
- un nombre premier P
- Q un nombre premier avec P-1,
- G = H^((P-1)/Q) mod P
- X un nombre
- Y = G^X mod P
Clef publique = P, Q, G et Y
Clef privée = X
Calcul de la signature (R,S) de M:
Choix d ’un nombre aléatoire k < Q
R = (G^K mod P) mod Q
S = (K^-1*(HASH(M) + X*R)) mod Q
Vérification de la signature (R,S): V == R
W = S^-1 mod Q
U1 = (HASH(M) * W) mod Q
U2 = (R*W) mod Q
V = ((G^U1 * Y^U2) mod P) mod Q
|
Presence des valeurs caracteristiques des fonctions de hash ; SHA-1,
MD5 , Ripe-MD.
_text:004015C1
lea ecx, [ebp+var_A4]
_text:004015C7
push ecx
_text:004015C8
call IniHash
On calcule le hash du nom mais la valeur renvoyée ne correspond
pas à ce qui été attendu... ( au fond peu importe
puisqu'il est assez simple de extraire le code et de le reutiliser tel
quel dans un keygen )
_text:004015EB
lea ecx, [ebp+var_A4]
_text:004015F1
push ecx
_text:004015F2
lea edx, [ebp+HashName]
_text:004015F8
push edx
_text:004015F9
call Hash
Les nombres :
AE2CCC8E5956DE7898143649944108EEFCA2C7EF909012BBh,
2FD2F3ABFAEDh
8DFC33DF82EDEFF56ABD1AE161BE17FBC1F403D5DF133106h, AA0D6424AD93D695435A3A09FAAFD5358620D37223EEAF39h
sont convertit au format Miracl utilisés par Miracl
_text:00401607
mov dword ptr [eax+220h], 40h
; base 64
_text:00401611
push offset aRizmjllw3niyfdzjleei7vyixQkbk7
_text:00401616
mov ecx, [ebp+var_40]
_text:00401619
push ecx
_text:0040161A
call CreatMiracl
_text:0040161F
add esp, 8
_text:00401622
push offset aP911bffr
_text:00401627
mov edx, [ebp+ShortNum]
_text:0040162A
push edx
_text:0040162B
call CreatMiracl
_text:00401630
add esp, 8
_text:00401633
push offset aJfwz34lt7Vqvrrhyb4x8h0a9xfezeg
_text:00401638
mov eax, [ebp+P]
_text:0040163E
push eax
_text:0040163F
call CreatMiracl
_text:00401644
add esp, 8
_text:00401647
push offset aQg1kjk2t1pvdwjojQVnyyg03ij7q85
_text:0040164C
mov ecx, [ebp+var_FC]
_text:00401652
push ecx
_text:00401653
call CreatMiracl
Il s'agit ensuite de reconnaitre les differentes etapes necessaires
à la verification d'une siganture DSA:
W = S^-1 mod Q
_text:00401673
mov ecx, [ebp+Part2SerialMcl]
_text:00401679
push ecx
_text:0040167A
mov edx, [ebp+Part2SerialMcl]
_text:00401680
push edx
_text:00401681
mov eax, [ebp+Part2SerialMcl]
_text:00401687
push eax
_text:00401688
mov ecx, [ebp+ShortNum]
_text:0040168B
push ecx
_text:0040168C
mov edx, [ebp+Part2SerialMcl]
_text:00401692
push edx
_text:00401693
call invS
U1 = (SHA(M) * W) mod Q
_text:0040169B
mov eax, [ebp+Result]
_text:004016A1
push eax
_text:004016A2
mov ecx, [ebp+ShortNum]
_text:004016A5
push ecx
_text:004016A6
mov edx, [ebp+ShortNum]
_text:004016A9
push edx
_text:004016AA
mov eax, [ebp+Part2SerialMcl]
_text:004016B0
push eax
_text:004016B1
mov ecx, [ebp+Part2SerialMcl]
_text:004016B7
push ecx
_text:004016B8
mov edx, [ebp+HashNameMcl]
_text:004016BE
push edx
_text:004016BF
call calcU
U2 = (R*W) mod Q
_text:004016C7
mov eax, [ebp+U2]
_text:004016CD
push eax
_text:004016CE
mov ecx, [ebp+ShortNum]
_text:004016D1
push ecx
_text:004016D2
mov edx, [ebp+ShortNum]
_text:004016D5
push edx
_text:004016D6
mov eax, [ebp+Part2SerialMcl]
_text:004016DC
push eax
_text:004016DD
mov ecx, [ebp+Part2SerialMcl]
_text:004016E3
push ecx
_text:004016E4
mov edx, [ebp+Part1SerialMcl]
_text:004016EA
push edx
_text:004016EB
call calcU
Vt = (G^U1 * Y^U2) mod P
_text:004016F3
mov eax, [ebp+V]
_text:004016F9
push eax
_text:004016FA
mov ecx, [ebp+var_40]
_text:004016FD
push ecx
_text:004016FE
mov edx, [ebp+U2]
_text:00401704
push edx
_text:00401705
mov eax, [ebp+var_FC]
_text:0040170B
push eax
_text:0040170C
mov ecx, [ebp+Result]
_text:00401712
push ecx
_text:00401713
mov edx, [ebp+P]
_text:00401719
push edx
_text:0040171A
call calcV
V = Vt mod Q
_text:00401722
mov eax, [ebp+ShortNum]
_text:00401725
push eax
_text:00401726
mov ecx, [ebp+ShortNum]
_text:00401729
push ecx
_text:0040172A
mov edx, [ebp+V]
_text:00401730
push edx
_text:00401731
call modulo
V == R ?
_text:00401736
add esp, 0Ch
_text:00401739
mov eax, [ebp+Part1SerialMcl]
_text:0040173F
push eax
_text:00401740
mov ecx, [ebp+V]
_text:00401746
push ecx
_text:00401747
call _compare
Resolution :
On peut ainsi identifier la valeur des differentes variables:
R = premiere moitié du serial
S = deuxieme moitié du serial
P =AE2CCC8E5956DE7898143649944108EEFCA2C7EF909012BB
G =8DFC33DF82EDEFF56ABD1AE161BE17FBC1F403D5DF133106
Y = AA0D6424AD93D695435A3A09FAAFD5358620D37223EEAF39
Q =A7DD75045151
Il ne nous reste plus qu'à resoudre le probleme du logarithme
discret: Y = G^X mod P
Discrete logarithm calculator
[ http://www.alpertron.com.ar/
]
The discrete logarithm problem is to find the exponent in the expression:
Base^Exponent = Power (mod Modulus).
This applet works only for prime moduli.
In this version of the discrete logarithm calculator only the Pohlig-Hellman
algorithm is implemented, so the execution time is proportional to the
square root of the largest prime factor of the modulus minus 1. The applet
works in a reasonable amount of time if this factor is less than 10^17.
NB: j'ai du supprimer les quelques lignes qui verifiaient la primalité
du modulo car d'apres isProbablePrime P n'est pas premier...
|
Quelques secondes plus tard, on obtient :
X = 40A6C8A2464A891E99DDBFCFC967BAFD4BAFA67B3ECEDC43
Keygen :
On a alors tout les elements necessaires au calcul d'une signature valide,
et donc a la creation d'un Nom/Serial valide:
Nom |
Amenesia |
Serial |
4A2B82-73F9AF-6CC2D1-CD1185 |
|