[pDrilI's Crypto keygenme #4 ]
par Amenesia

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