Résoudre Progressive Keygenme#2 de Fargoth.

Par Sp0ke

 

 

         

Outils :

 Progressive_KeygenMe#2

Ollydbg modifié + (le plugin Data ripper)                          

 Masm32

 Et savoir un peu coder dans le langage avec le quel vous êtes le plus à l'aise.

« Pourquoi savoir coder alors que l’on cherche un serial » : me direz-vous ?

Et bien vous allez très vite comprendre pourquoi par la suite.

Bonjour à toutes et à tous dans ce tutorial nous allons tenter d’analyser le Progressive KeygenMe#2 de Fargoth

 

 

Après avoir ouvert le progressive KeygenMe #2 dans Ollydbg on va le lancer (F9) et remplir les champs
Nom et serial dans les editbox(s) respectives pour moi « spoke »
       

Et « 123456789  » .Oui il faut mettre un nom de 5 caractères minimum pour le Nom sinon vous aurez droit au message suivant :

 

<image 1>

 

Pour moi j’ai donc mis :

<image 2>

On regarde si notre couple Nom/Serial entré est correcte en appuyant sur le bouton « Check »
          
mais hélas non nous avons droit au message qui nous fait comprendre gentiment  qu’il ne faut pas rêver
          
mais qu’on peut toujours « retenter sa chance » :
 

<image 3>

 

Nous allons donc voir comment ce présente l’algorithme du keygenMe#2 de Fargoth en vidéo => Vidéo 1
            
Donc dans cette vidéo nous avons :
vu que le serial est en fait composé de deux parties séparées par un tiret «  - «  ou appelé parfois séparateur.
Appris comment poser des Break points sur toutes les occurences d’une fonction (Api) =>Vidéo 2
Appris ce qu’est la fonction GetDlgItemTextA.(Vous pouvez relire cette définition en cliquant sur l’Api)
Appris la significations de certains sauts conditionnels.
              
Récapitulatif des Branchements:
            Les sauts conditionnels

Les branchements conditionnels (ou sauts conditionnels) permettent au processeur de traiter             
l’instruction située à un emplacement mémoire indiqué si une certaine condition est vérifiée.

Dans le cas contraire (condition non réalisée), le processeur ignorera cette instruction, il traitera donc l’instruction suivante.

La (ou les) condition(s) à satisfaire dépend(ent) de l’état d’indicateurs.

            
Ainsi les branchements conditionnels doivent généralement être placés après une opération
           

qui va modifier l’état d’un ou plusieurs indicateurs (une instruction CMP ou autre).

 

Selon l’intitulé de l’instruction, les conditions à satisfaire sont différentes :
JA (Jump if above, ce qui signifie saute si au-dessus)
effectue un saut si ZF=0 et CF=0

JB (Jump if Below, ce qui signifie saute si en dessous)
effectue un saut si CF=1

JBE (Jump if Below or Equal, ce qui signifie saute si en dessous ou égal)
effectue un saut si ZF=1 ou CF=1

JE (Jump if Equal, ce qui signifie saute si égalité)
effectue un saut si ZF=1

JG (Jump if Greater, ce qui signifie saute si supérieur)
effectue un saut si ZF=0 et SF=OF

JLE (Jump if Lower or Equal, ce qui signifie saute si inférieur ou égal)
effectue un saut si ZF=1 ou SF différent de OF

JNE/JNZ (Jump if Not Equal, ce qui signifie saute si non-égalité)
effectue un saut si ZF=0

JA (Jump if above, ce qui signifie saute si au-dessus)
effectue un saut si ZF=0 et CF=0
JG (Jump if Greater, ce qui signifie saute si supérieur)
effectue un saut si ZF=0 et SF=OF
 

Petites explications supplémentaires  (Merci mars)   ;)
--> la différence entre ces deux sauts, c'est le signe
JA et (JB) c'est pour des valeurs non signés
JG et (JL) c'est pour des valeurs signés

c'est quoi des nombres signés? --> c'est la possibilté de travailler avec des nombres négatifs
quand on travaille avec un dword signé:
--> de 00000000 à 7FFFFFFF c'est positif
--> de 80000000 à FFFFFFFF c'est négatif
quand on travaille avec un word signé:
--> de 0000 à 7FFF c'est positif
--> de 8000 à FFFF c'est négatif
quand on travaille avec un byte signé
--> de 00 à 7F c'est positif
--> de 80 à FF c'est négatif

c'est l'instruction cmp ou test qui permet de savoir si on travaille
sur un dword, word ou un byte
si on al = D8 et bl = 36 en hexadecimal
cmp al, bl
jg ici (jump if great --> saute si superieur avec nombres signés)
--> le saut en ici ne se fait pas car avec jg, on travaille
sur des nombres signés, on travaille sur des byte (al et bl)
al = D8 en hexa signé --> soit -40 en décimal
bl = 36 en hexa signé --> soit 54 en décimal
-40 < 54 donc le saut ne se fait pas

par contre, si on a l'instruction suivante
cmp al, bl
ja ici (jump if above --> saute si superieur avec nombres non signés)
al = D8 en hexa non signé --> soit 216 en décimal
bl = 36 en heax non signé --> soit 54 en décimal
216 > 54 donc le saut se fa

Récapitulatif de la boucle qui créé la 1ere   partie du serial:                   

Donc pour résumer la boucle ci-dessous  xor le 1er caractère du Nom par le suivant et                   

 le résultat par le caractère suivant et ainsi de suite comme ceci:     

La boucle ci-dessus  <image 4> effectue les calculs suivants :   

73 xor 70  = 3 ==> 3 xor 6F = 6C ==> 6C xor 6B = 7 ==> 7 xor 65 = 62

 

 

<image 4>

 

Le Nom à été placé dans le registre ESI           

      

en Ascii  :

s

p

o

k

e

en Hexa  :

73

70

6F

6B

65

<Tableau 1>

 

 

Le  XOR

Qu’est ce que c’est ? :


Le XOR est un opérateur logique qui correspond à un « OU exclusif » : c’est le (A OU B)                                            

 qu’on utilise en logique mais qui exclue le cas où A et B sont simultanément vrais. Voici sa table de vérité :

 

Table de vérité du XOR

A

B

(A XOR B)

(Faux) 0

(Faux) 0

(Faux) 0

(Faux) 0

(Vrai) 1

(Vrai) 1

(Vrai) 1

(Faux) 0

(Vrai) 1

(Vrai) 1

(Vrai) 1

(Faux) 0

<Tableau 2>

 

Si on applique la table de vérité <Tableau 2> ça donne ceci ci-dessous <Tableau 3>:

 

Formats

Hexa

Binaire

Hexa

Binaire

Hexa

Binaire

Hexa

Binaire

XOR

73

01110011

3

00000011

6C

01101100

7

00000111

70

01110000

6F

01101111

6B

01101011

65

01100101

Résultats

3

00000011

6C

01101100

7

00000111

62

01100010

<Tableau 3>

 

Vous voyez en fait le calcul du XOR est vraiment très simple une fois les caractères du Nom convertis en Binaire.                      

Je considère que vous savez ce qu’est un XOR et comment il fonctionne.                    

Donc le  serial se présente comme ceci : 62-xxxxxx                                             

Maintenant ce qu’il nous manque pour avoir le message « Good boy » c’est la 2ème partie du serial soit les 6 caractères restants,                    

qui à mon humble avis se génère dans le call où l’on s’est arrêté à la fin de la vidéo soit à l’adresse 00401128 :

 

00401128 |. E8 A5000000 CALL progress.004011D2


 

 

           

 

Nous allons donc retourner dans Ollydbg et poser un Break point dessus et entrer dedans avec la touche F7 afin de comprendre ce qu’il s’y

passe. Nous remplirons les editbox(s) avec comme couple:                         

Name : spoke                          Serial : 62-456789                              

Nous allons donc analyser la 2ème  partie de l’algorithme qui génère un hash avec la  2ème partie du serial en regardant cette vidéo.=>  Vidéo 3

Récapitulatif de la boucle qui créé un hash sur  la 2ème partie du serial:

 

<image 5>

 

 

 

<image 6>

   

On a vu que dans cette boucle il y a une table qui est utilisée à partir de l’adresse 004011F6 et cette table en question commence en 0040224B

Voici le lien du fichier ou ce trouve la table ==> ici                      

On a vu aussi qu'au final il faut que AL soit égal à BL pour obtenir le message "Good boy" donc si on a bien compris il faut dès le départ avoir la

2ème bonne partie du serial. "Pas évident hein ?? " ,et bien le seul moyen pour ma part de l'obtenir est de brute forcer la boucle <image 5> .

Pour cela  il nous faut générer aléatoirement au départ les six derniers caractères du serial avant le passage de la boucle <image 5>.

Une dernière chose que Fargoth nous oblige à faire pour le générateur aléatoire c’est que celui-ci ne prenne pas en compte les caractères

exotiques tel que  «  (ù*$=)ç\ »  etc…                      

On le voit bien lors des vérifications au début <image 7> par exemple 46h = « F »  et 29h = « )» .                       

Donc il faut que l’on fasse une fonction Rand qui choisira dans une table les caractères suivants : « 0123456789ABCDEF »

 

 

<image 7>

 

ensuite reproduire la boucle <image 6> celle qui additionne les valeurs Hexadécimales des caractères du Nom et la boucle  <image 4>

Et aussi reproduire la comparaison de AL à BL et de mettre après cette comparaison un saut conditionnel qui saute au début du générateur

aléatoire des 6 dernier caractères du serial tant que AL et BL ne sont pas égaux. Et dès que AL et BL sont enfin égaux faire en sorte que

le brute force nous affiche les 6 derniers caractères que le générateur aléatoire a créé et qui doivent évidement êtres bons.

Pour plus de clarté voici un schéma ci-dessous:

 

 

 

              

 Voici ce que vous avez comme beau message après avoir entré un bon serial cool non ?

 

 

                      

Voici le keygen/Brute Force =>Keygen  ==> Bugfixed le Vendredi 6 Mars  Merci Fargoth.

Merci à Fargoth pour ce KeygenMe#2 très sympa et de m'avoir aidé à corriger le bug concernant les Noms à 6 caractères et

les Noms du genre "plouplou" ou "glouglou" ceux-ci donnaient un bug à mon keygen il fallait juste retranscrire la boucle du xor du Nom telle

qu'elle était dans son code et sans oublier de mettre le chiffre du nombre des caractères du Nom dans un buffer qui est appellé par ECX dans

cette boucle. Le keygenme de Fargoth  m’en aura  fait "baver"jusqu'au bout héhé mais au final je l’ai vraiment apprécié. 

 

Remerciements à :
Coolmen, Kirjo, Z!PPer, mars, taloche,Tytan, Néo, Hibou28, Burner et ainsi que tous les membres d’ xtx,
uLysse_31/FFF, Dynasty, donald, baboon,  Ezéqui3l
et tous les membres de DeezDynasty.
Ainsi que tous les membres de ForumCrack.
Sp0ke
xtx TeaM   Février 2009.
Bonne lecture à tous.