Résumons le fonctionnement du keygenme. Tout d'abord, au lancement du binaire, 3 octets sont générés de façon pseudo-aléatoire et sont stockés en 405103, 405104 et 405105. Puis, l'utilisateur actionne les boutons de la coloquinthe dans un certain ordre. Ceci a pour effet à chaque clic de stocker un octet dans une table située en 4050FF. Une fois que le user a réalisé une combinaison de 4 clics, le binaire vérifie la validité de la séquence en utilisant une TABLE DE VERIFICATION. Plutôt que d'entrer dans de longues explications, voici en images le déroulement de la vérification du serial :
Un cadre se déplace sur les deux tables situées en 4050FF et 405103. La routine va donc vérifier sur la valeur indiquée par la petite flèche noire du cadre mobile est égale à la valeur correspondante dans la table. Pour ce faire, la valeur récupérée dans la première table (4050FF) représente la colonne d'une TABLE DE VERIFICATION tandis que la seconde valeur situé dans la seconde table (405103) représente la ligne de cette même table de vérification. Si on prend la valeur en 4050FF, nous avons 0 qui indique donc la colonne 0 de la TABLE DE VERIFICATION. EN 405103, nous avons 2 qui indique la ligne 2 de cette même TABLE. La valeur située en (0;2) dans la TABLE est le nombre 2. La valeur indiquée par la flèche noire du cadre mobile doit donc valoir 2 également.Dans mon exemple, tout est correct sauf la dernière valeur (le dernier bouton activé). Notez également que la première valeur n'est pas testée ici mais nous allons voir qu'elle peut toujours être égale à 0.
En réalité, vous imaginez bien que le check du serial n'est pas présenté de façon aussi explicite. Il y a ce qu'on appelle un "fake" dans la routine, c'est-à-dire un élément ajouté à la routine pour rendre les choses plus complexes à analyser. Cela dit, il ne sert à rien et nous verrons que nous n'en avons pas besoin pour coder le keygen.
Voici le début de la routine de vérification. ESI représente le décalage de notre cadre.
004016B3 CMP BYTE PTR DS:[ESI+4050FF],0 004016BA JNZ SHORT esoquynt.004016FF 004016BC CMP BYTE PTR DS:[ESI+405100],1 004016C3 JNZ SHORT esoquynt.004016FF 004016C5 CMP BYTE PTR DS:[ESI+405103],1 004016CC JNZ SHORT esoquynt.004016F5 004016CE OR ESI,ESI 004016D0 JNZ SHORT esoquynt.004016DC 004016D2 PUSH 1337C0DE 004016D7 JMP esoquynt.00401C90 004016DC CMP ESI,1 004016DF JNZ SHORT esoquynt.004016EB 004016E1 PUSH 111347 004016E6 JMP esoquynt.00401C90 004016EB PUSH 0F1237 004016F0 JMP esoquynt.00401C90 004016F5 PUSH 0BADB07 004016FA JMP esoquynt.00401C90
La routine commence par 3 comparaisons. Regardez la TABLE DE VERIFICATION et vous allez comprendre que ces séquences de comparaisons reviennent à tester la table. Si la comparaison réussit, une valeur est poussée sur la pile. Si la comparaison échoue, BADB07h est poussé. Quoiqu'il arrive, on se moque de savoir quelle valeur est poussée, il faut que 3 comparaisons successives réussissent.
A la fin de la routine de check, nous pouvons voir ceci :
00401C9A POP EAX 00401C9B POP EBX 00401C9C POP ECX 00401C9D ADD EAX,EBX 00401C9F ADD EAX,ECX 00401CA1 CMP EAX,1357E65C 00401CA6 JNZ SHORT esoquynt.00401CC5 00401CA8 PUSH DWORD PTR DS:[40547B] 00401CAE PUSH 0 00401CB0 PUSH 172 00401CB5 PUSH 208 00401CBA PUSH DWORD PTR DS:[405368] 00401CC0 CALL SendDlgItemMessageA 00401CC5 RETN
Les valeurs poussées sur la pile sont dépilées et ajoutées les unes aux autres. Si par malheur l'une d'elle vaut BADB07h, ceci signifie que l'une des comparaisons s'est mal passé et donc la somme ne sera pas égale à la valeur attendue 1357E65C. Si le test réussit, un message est envoyé à la fenêtre pour afficher le petit logo de la victoire.
Vous voyez donc que les valeurs poussées n'ont aucun intérêt et font double emploi avec les comparaisons. Il s'agit donc d'un fake !