Dans cette mission nous était donné un exécutable Windows, avec une combinaison de 9 chiffres à retrouver.
Passons tout d’abord le binaire sous PEiD afin de détecter d’éventuelles protections.
Le crackme est packé UPX. On l’unpack de manière très classique : on load le binaire sous OllyDBG, puis on place un breakpoint sur le JMP de fin qui pointe vers l’OEP :
On presse F9 pour lancer le programme et l’arrêter au breakpoint : ainsi, l’unpacking, en mémoire, a été fait. En faisant un F8, on tombe sur le programme original. Le point d’entrée d’origine se situe donc en 0040A138. On dump le processus avec OllyDump (sans Rebuild Import). On lance le binaire packé, puis on ouvre ImportREC, et on y attache son processus. On rentre l’OEP : A138, on clique sur « IAT AutoSearch », « Get Imports », puis « Fix Dump », où on sélectionne le dump précédemment effectué avec OllyDump. Voilà, notre crackme est unpack !
Commençons maintenant l’épreuve. Le crackme utilise en fait une animation Flash pour l’interface (séléction de la combinaison, son, etc.). C’est ensuite le programme qui gère la vérification de cette combinaison de 9 chiffres.
En avançant un tout petit peu avec quelques F8 et en regardant ensuite dans les différents calls (Search for -> All Intermodular Calls), quelques fonctions nous interpellent, comme isalpha ou strchr. On pose un breakpoint en 04072A9 et on démarre le programme. On rentre une combinaison du style 123456789. Le programme s’arrête bien à l’endroit souhaité :
Dans les registres, on peut apercevoir quelque chose d’assez intéressant.
Allons en apprendre un peu plus sur cette chaine de caractères, en faisant un clic droit sur 004E5341, puis « Follow in Dump ».
Tiens, du XML avec 9 nombres! Ceux-ci sont sûrement issus du SWF : ces nombres seraient donc ce que nous avons entré. On peut donc établir la correspondance suivante :
123456789 969196434
On relance le programme, et on fait des tests sur plusieurs entrées. On peut établir plusieurs correspondances :
000000000 406728315 111111111 517839426
Tiens : avec des 1, le nombre correpond au même qu’avec celui des 0, mais avec +1 à chaque chiffre.
000000001 406728316
En modifiant le dernier digit, c’est bien le dernier digit qui est modifié aussi.
100000000 406728415
Ah, cette fois-ci c’est pas le premier chiffre qui a changé (on se base sur « 406728315 » qui est le résultat de « 000000000 »), mais le 7ème chiffre.
On peut déjà, à partir de là, comprendre la logique de transformation : les digits sont permutés, puis on y ajoute, dans l’ordre, 4, 0, 6, 7, 2, 8, 3, 1 et 5.
En établissant les correspondances suivantes, on peut retrouver la permutation effectuée :
# Cas normal 000000000 406728315 # Le 7ème digit change 100000000 406728415 # Le 8ème digit change 010000000 406728325 # Le 3ème digit change 001000000 407728315 ...
La permutation finale se trouve être 783412569.
En résumé : notre combinaison est permutée selon la permutation ci-dessus, puis à chaque digit, on ajoute 4, 0, 6, 7, 2, 8, 3, 1 et 5 (si on dépasse 9, on revient à 0 ; on travaille donc modulo 10).
Pour revenir en arrière, nous n’avons qu’à soustraire la clé, puis refaire la permutation. Mais jusqu’ici, nous n’avons encore aucune trace de comparaison ou quoi que ce soit : continuons donc l’analyse du programme à la recherche d’une comparaison.
En 0404190, on trouve une routine assez intéressante. Il faut la reconnaitre : c’est un calcul de hash MD5. Posons un breakpoint dessus, puis lançons le programme avec une combinaison bidon du style « 123456789 » (qui sera transformée en « 969196434 »). Le programme s’arrête juste avant le calcul du hash MD5. À moins que vous voulez vous taper tout le calcul, vous pouvez poser un second breakpoint juste après, aux alentours de 04048D3. On sort de la routine en avançant à coups de F8, puis on tombe vers une petite boucle en 00404B70 qui s’occupe de placer le MD5 en 0018F1AC. Après les 16 itérations de la boucle, le md5 calculé est (en héxadécimal) :
3504BF0AA09DA5294D6CE1F0294A6A0D
…ce qui correspond bien au hash MD5 de « 969196434 ».
Un peu plus loin, en 004022C2, se situe une boucle un peu étrange (qui compte de 0x1337 à 0x1347… ce qui fait bien 16 octets) qui s’occupe de comparer le md5 calculé avec un autre md5 dans la mémoire, en 00410378 :
AE7AA70CDABAAB3B76B9694B51A92732
Le bruteforce de ce hash serait un peu long (10 ^ 9 possibilités). Heureusement, des sites comme md5decrypter.co.uk nous donne le plaintext de ce hash assez vite :
279451446
Il ne reste plus qu’à appliquer la transformation inverse sur ce nombre.
Tout d’abord, on soustrait la clé (406728315) sur du modulo 10, ce qui donne :
n = "279451446" k = "406728315" p = '' for i in range(9): p += str((int(n[i]) - int(k[i])) % 10) print p
873733131
On applique maintenant la permutation 783412569, qui donne la combinaison finale :
133787331
Wooot! On valide avec 133787331.
Enjoy.