|
Type de Protection: Name
/ Serial Outils utilisés: Ollydbg v1.09c, RSATool v2 Langage: Microsoft Visual C++ 6 |
Sommaire :
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.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; xor eax, eax or al, al inc edx @fin:
|
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]
où ? 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.
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 mov ecx, offset number push offset number+5 mov edx, offset number+5 mov edx, offset number mov ecx, eax invoke _BigCreate, 0 invoke _BigCreate, 0 invoke _BigCreate, 0 invoke _BigCreate, 0 invoke _BigIn,addr RSA_N, 16d, Big_N invoke _BigPowMod, Big_Serial, Big_D, Big_N, Big_SerialRSA |
|
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 !