KeygenMe #02 de PDrili
Solution par Bigbang

Type de Protection: Name / Serial
Outils utilisés: Ollydbg v1.09c, RSATool v2
Langage: Microsoft Visual C++ 6

Sommaire :

I.Analyse du KeygenMe
II. Codage du keygen

I. Analyse du KeygenMe

Cet exe n'étant pas compressé, nous pouvons l'ouvrir tel quel dans Olly.
On cherche les appels à GetDlgItemText (Ctrl + N), on sélectionne GetDlgItemText, on presse <Enter>.
Il y a un premier appel à la fonction en 00401077.
Il est chargé de récupérer le nom dans un buffer en 0012FAFC.
On pose un bpx sur l'appel.
On fais F9.
On rentre un nom ("bigbang") et un serial ("123456").
On click sur Check.
Olly break.
Trace Over (F8).
L'appel a bien récupérer le nom.

Un deuxième appel est réalisé en 004010AD.
Il récupère le serial rentré en 0012FA98.

Si tout c'est bien passé, on arrive en 004010D6.
La séquence d'instructions qui suit stocke le nombre de caractère dans le nom.
En 004010F1, le test vérifie qu'il y a au moins un caractère dans nom. (Dans notre cas, ECX vaut 6)

La boucle qui suit calcule un nombre en fonction des caractères contenus dans le nom.

Pour chaque caractère c de Nom, on calcule le nombre S, tel que :

S(n) = ((((((c * 10h ) + c ) * 10h + c ) * 10h + c ) * 5 ) * 2 ) + S(n-1)
et S(0) = 0

On peut simplifier cette expression : ((((((c * 10h ) + c ) * 10h + c ) * 10h + c ) * 5 ) * 2 )
(Toutes les lignes sont équivalentes : )

((((((c * 10h ) + c ) * 10h + c ) * 10h + c ) * 5 ) * 2 )
(((c * 17 * 16 + c ) * 16 + c ) * 10 )
(((c * 273 ) * 16 + c ) * 10 )
c * 43690

NB : 46690d = 0AAAAh

Pour calculer ce nombre, j'ai codé une routine ASM très simple : Calculate.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
calculate PROC
;
; Auteur: Bigbang
;
; Calcule le nombre pour le keygen
;
; Paramètres: - EDX: Pointe sur la chaine
; Retour: - ECX: nombre en question
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

xor eax, eax
xor ecx, ecx
@deb:
movzx eax, BYTE PTR [edx]

or al, al
je short @fin

imul eax, 0AAAAh
add ecx, eax

inc edx
jmp short @deb

@fin:
mov eax, ecx

ret


calculate ENDP

Ensuite, une boucle vérifie que le serial rentré est alphanumérique.

Si c'est le cas, une fonction est appelée 2 fois avec comme paramètre, la première fois un pointeur sur la chaine "7E2BDC8ED8856EE745A9D6F93E143B7ACE202999" et la deuxieme fois sur "10001".

A en croire mon intuition, RSA serait utilisé dans ce keygenme. Mais poursuivons tout de même.

Juste après le deuxième appel, une nouvelle fonction est appelée (en 004011EB). Elle prends 4 paramètres : un premier qui pointe sur un bignum vide, un deuxieme qui pointe sur le bignum 7E2BDC8ED8856EE745A9D6F93E143B7ACE202999, un troisième sur le bignum 10001 et quatrième qui pointe sur le serial, précédemment convertit en bignum (en 004011BE).

Tout porte donc à croire que la fonction va crypter le serial rentré avec RSA.

Pour en avoir le coeur net, on ouvre RSA Tool et on rentre 7E2BDC8ED8856EE745A9D6F93E143B7ACE202999 dans le champ N.
Le programme nous indique 159 bits ce qui est factorisable sous un délai très raisonnable.
On lance la factorisation.
Le résultat arrive rapidement :
7E2BDC8ED8856EE745A9D6F93E143B7ACE202999 = CBCEDFDFC9A4E52CDB4B * 9E7B52E33905ADBD7C2B
Le deuxième nombre (10001) est très probablement l'exposant public.
On le rentre et on calcule D.
On a D = 3FC69E031A914000E925FC61F2BF888F410EB07D
L'hypothèse RSA est donc confirmée.

On a ceci : Serial_RSA = Serial ^ 10001 Mod 7E2BDC8ED8856EE745A9D6F93E143B7ACE202999

Une nouvelle fonction et ensuite appelée : elle copie le résultat 0012FA98.
On ajoute le zéro terminal.

Le programme effectue alors une comparaison entre les quatre premiers caractères du Serial_RSA et la chaîne FHCF.
54770B67 xor 12344321 = 46434846 (FHCF).

Donc les quatre premiers caractères du Serial_RSA doivent être FHCF.

Si vous avez pris 123456 comme serial, le Serial_RSA ne commence pas par FHCF.
Donc arrivé au JNZ, ça saute.
Pour y remédier, changez le Zero Flag.
Positionnez-le à 1.
Ainsi le programme se continue comme si le Serial_RSA commençait par FHCF.

Le programme récupère le nombre calculé au début du code dans ECX et fais pointer EDX sur le nom (ici, "bigbang")
Une fonction est appelée et convertit le contenu de ECX en chaine ASCII affichable. Remarquez tout de même que les lettres sont en minuscules.
Le programme nettoie la pile puis fais pointer EAX sur le cinquième caractère du Serial_RSA et ECX sur la chaine précédemment convertit.

lstrcmp est appelée. Elle effectue la comparaison entre le Serial_RSA à partir du cinquième caractère et entre le nombre calculé au début convertit en chaine ASCII.

Les deux chaines doivent être les mêmes pour afficher le message de réussite.

Bilan sur le serial :

on a : Serial_RSA = Serial ^ 10001 Mod 7E2BDC8ED8856EE745A9D6F93E143B7ACE202999
et Serial_RSA est de la forme [FHCF] ? [xxxxxx]
? représente un caractère alphanumérique quelconque
et [xxxxxx] le nombre calculé au début convertit en chaine ASCII

On devra aussi appliqué à Serial_RSA le décryptement RSA de manière à obtenir le serial à rentrer dans le keygenme.
Nous avons tous les éléments pour le faire :
N = 7E2BDC8ED8856EE745A9D6F93E143B7ACE202999 (base 16)
D = 3FC69E031A914000E925FC61F2BF888F410EB07D (base 16)

Donc finalement, Serial = Serial_RSA ^ D Mod N

Au début du code, le Serial est convertit en bignum à partir de la base 60 (ce qui explique que les 'y' et les 'z' rentrés dans le champ serial entrainent la fermeture de l'exe). Il faudra terminer par la conversion de Serial en base 60 avant de l'envoyer dans l'Edit.

II. Codage du keygen

Je l'ai codé en ASM en utilisant la biglib codée par Roy.
Voici la partie essentielle du keygen (cf. keygen.asm pour les commentaires) :
Sources : _source_keygen.zip

mov edx, offset szname
call calculate

mov ecx, offset number
mov DWORD PTR [ecx], 46434846h
add ecx, 4
mov BYTE PTR [ecx], 30h

push offset number+5
push eax
call bnultohexa

mov edx, offset number+5
call maj2min

mov edx, offset number
call szlen

mov ecx, eax
mov esi, offset number
mov edi, offset number2
call ConvertToASCII

invoke _BigCreate, 0
mov Big_N, eax

invoke _BigCreate, 0
mov Big_D, eax

invoke _BigCreate, 0
mov Big_Serial, eax

invoke _BigCreate, 0
mov Big_SerialRSA, eax

invoke _BigIn,addr RSA_N, 16d, Big_N
invoke _BigIn,addr RSA_D, 16d, Big_D
invoke _BigIn,addr number2, 16d, Big_Serial

invoke _BigPowMod, Big_Serial, Big_D, Big_N, Big_SerialRSA
invoke _BigOut,Big_SerialRSA,60d,addr szGood

 

bigbang / AmTHxr0N5RuI56RHYTw0Tm50Nkp

Ciao...

Greetz :
- Membres de FFF de la ShmeitCorp
- tE! pour son RSA tool

- Tous ceux qui passent sur le nouveau CrFF
- elooo, jB, the Analyst, SpYflaX, GBillou, Darus, SeVen, SynApsus, magicalbubble et les autres :)
- Shad0w, Tyrael, ex0d et vous bien sur !

Bigbang