[cRYPTO KEYGENME  v1.0 by bLaCk-eye ]
by Amenesia//tkm!

  Le programme est packé avec FSG (PEiD)... 

seg001:0041C306 loc_0_41C306: 
seg001:0041C306                 dec     byte ptr [esi]
seg001:0041C308                 jz      near ptr dword_0_401000
seg001:0041C30E                 push    esi

On remplace le jz vers le OEP par une boucle infinie, puis dump et reconstruction de la table d'import...



Premiere étape, touver comment les informations entrées sont recuperées. Là encore, rien de compliqué une petite recherche de l'API GetWindowTextA nous mene par ici, l'analyse peut commencer:

seg000:00401B05                 push    ebx             ; hWnd
seg000:00401B06                 call    GetWindowTextLengthA
seg000:00401B0B                 cmp     eax, 0Ah
seg000:00401B0E                 jbe     loc_0_401BF0

La chaine doit comporter au moins 10 caracteres...

seg000:00401B1B                 push    64h
seg000:00401B1D                 push    esi      ; Buffer <= Information entrée
seg000:00401B1E                 push    ebx
seg000:00401B1F                 GetWindowTextA

 On recupere la chaine...

seg000:00401B24                 xor     ebx, ebx
seg000:00401B26                 xchg    eax, ecx
seg000:00401B27                 lea     edi, [ebp+var_DC]
seg000:00401B2D 
seg000:00401B2D loc_0_401B2D: 
seg000:00401B2D                 movsx   eax, byte ptr [ebx+esi]
seg000:00401B31                 cmp     al, 23h                    ;  car == "#" ?
seg000:00401B33                 jz      short loc_0_401B3B
seg000:00401B35                 mov     [ebx+edi], al
seg000:00401B38                 inc     ebx
seg000:00401B39                 jmp     short loc_0_401B3D
seg000:00401B3B loc_0_401B3B: 
seg000:00401B3B                 jmp     short loc_0_401B3F
seg000:00401B3D loc_0_401B3D: 
seg000:00401B3D                 loop    loc_0_401B2D
seg000:00401B3F 

Dans un premier temps la clef est copiée caractere par caractere jusqu'à ce qu'on tombe sur "#".

seg000:00401B3F loc_0_401B3F: 
seg000:00401B3F                 xor     al, al
seg000:00401B41                 mov     [ebx+edi], al
seg000:00401B44                 mov     [ebp+var_E0], ebx
seg000:00401B4A                 push    offset dword_0_4042C8
seg000:00401B4F                 push    ebx                    ; longueur 1ere partie
seg000:00401B50                 push    edi                    ; 1ere partie de la clef
seg000:00401B51                 call    MD5

Puis la partie precedement copiée est hashée ( visiblement à coup de MD5, mais importe cette partie de l'algo n'a pas besoin d'etre "inversé" )
 

seg000:00401B56                 mov     eax, ds:dword_0_4042C8
seg000:00401B5B                 xor     eax, ds:dword_0_4042D4
seg000:00401B61                 and     eax, ds:dword_0_4042CC
seg000:00401B67                 imul    eax, ds:dword_0_4042D0
seg000:00401B6E                 mov     [ebp+var_E4], eax

Le resultat du hash est utilisé pour generer une nouvelle valeur:
K = ( ( hash[0] xor hash[3] ) and hash[1] ) * hash[2]
 

seg000:00401B74                 lea     ebx, ds:4042B8h
seg000:00401B7A                 mov     edx, [ebx+8]
seg000:00401B7D                 push    edx
seg000:00401B7E                 push    eax             ; key
seg000:00401B7F                 call    bigCreat

La valeur est affecté a un bignum. (Big1) A premier vue il semble que ce keygenme utilise la librairie ecrite par roy... 

seg000:00401B84                 mov     edi, esi
seg000:00401B86                 add     edi, [ebp+var_E0]
seg000:00401B8C                 inc     edi
seg000:00401B8D                 mov     edx, [ebx+0Ch]
seg000:00401B90                 push    edx             ;  Big
seg000:00401B91                 push    10h             ; base
seg000:00401B93                 push    edi             ; 2éme partie des info. entrées
seg000:00401B94                 call    bigIn

La partie de la chaine se situant apres le "#" est elle aussi affecté a un bignum. ( Big2 )

seg000:00401B99                 push    dword ptr [ebx+0Ch] ; > BigR
seg000:00401B9C                 push    dword ptr [ebx]     ; < DB10266AB0FD5B
seg000:00401B9E                 push    dword ptr [ebx+0Ch] ; < Big2
seg000:00401BA1                 push    dword ptr [ebx+4]   ; < CC3183A81DF91
seg000:00401BA4                 call    bigPowMod

 Le fait d'avoir reconnu la libraire utilisée nous facilite le travaille ;)
BigR = CC3183A81DF91^Big2 mod DB10266AB0FD5B

seg000:00401BA9                 push    dword ptr [ebx+0Ch] ; < BigR
seg000:00401BAC                 push    dword ptr [ebx+8]   ; < Big1
seg000:00401BAF                 call    bigCmp
seg000:00401BB4                 or      eax, eax
seg000:00401BB6                 jnz     NOTREGISTRED

Donc le serial est valide si:  Big1 == CC3183A81DF91^Big2 mod DB10266AB0FD5B
La valeur de Big1 est obtenue à partir d'une operation de hash, il est donc "difficile" d'obtenir la chaine correspondante au Big1.

Les valeurs considerées etant assez petites on peut resoudre le logarithme discret (ie determiner Big2 à partir de Big1 ).
L'ordre du groupe generé est DB10266AB0FD5A = 2*9D*9C7*1244426C27... on peut donc utiliser l'algorithme de Pohlig-Hellman ( l'algo de Pollard rho met quasiment 1/4h ) et obtenir la solution en quelques ms ;) 

Pour plus d'infos, cherchez le mémoire: "Algorithmes de calcul de logarithme discret dans les corps finis" ou le livre "Handbook of Applied Cryptography"...



Key Amenesia//tkm!#779EE69AD541C3

Amusez vous bien... ;)