CrackMe de Uriel
par Kharneth
 
Outils utilisésPublicCible
 - PEId
 - OllyDbg
 - Calculatrice
 - Papier, Crayon, Cerveau 5.0
 Débutant en Cracking
ayant des connaissances de base en programmation
 CrackMe_Uriel
 
1 - PEId 

      Comme d'habitude, on commence par une analyse rapide avec PeId pour vérifier que le programme n'est pas compressé ou crypté. Il ne l'est pas. PEId nous signale juste que c'est une application console.
      On va donc le charger dans OllyDbg.

2 - OllyDbg 

      On commence par chercher des chaînes de caractères intéressantes et on voit "...Entrez le mot de passe..." et "Bonne reponse..." dans la liste des chaînes référencées. On double-click sur la première et on arrive sur La routine! Tout ce qu'on a besoin de voir se touve dans ces quelques lignes:

      La fonction printf affiche le texte qui nous demande d'entrer un mot de passe. La fonction scanf récupère ce mot de passe sous forme d'entier, indiqué par le paramètre "%d". Ensuite, on a une boucle, en 0x00401312, qui doit effectuer des opérations sur le pass, puis une comparaison en 0x00401343 suivie d'un saut conditionnel qui nous envoie sur une fonction printf qui affiche "Mauvais pass".
      Comme le code est clair et assez court, on va se le frapper en Dead Listing. OllyDbg n'est pas vraiment fait pour, mais je n'aime pas l'interface de W32Dasm ou de IDA. Je trouve le code beaucoup plus clair sous OllyDbg et puis je ne sais pas encore me servir correctement de IDA. On peut malgré tout insérer des commentaires facilement en double-clickant sur la ligne qu'on veut dans la zone commentaire (la plus à droite dans la fenêtre).
      En fait, on va prendre chaque ligne en essayant de comprendre ce qu'elle fait. Pour que ce soit plus clair, on va noter en commentaire l'équivalent en langage C de chaque instruction importante. Au final, on aura un listing C qui devrait être assez proche du code original. Mais comment déterminer qu'une instruction est intéressante? Eh bien, il faut comprendre un minimum l'assembleur et le fonctionnement d'un programme. So, let's go!

      Les 2 premières lignes sauvegardent l'état de la pile et sont normalement présentes au début de chaque routine appellée par un CALL. Les 2 dernières instructions LEAVE et RETN restaurent l'état de la pile et continuent l'exécution du programme après le CALL. Ensuite, toutes les instructions du style ADD ESP, XX correspondent à des déplacements dans la pile et ne nous concernent pas.

      On commence donc l'analyse à la 5ième instructions avec 3 initialisations de variable. C'est à dire que des valeurs sont placées en mémoire à une certaine adresse. On remarque que la 2ième valeur est utilisée comme compteur dans la boucle et que la 3ième valeur est utilisée dans l'instruction de comparaison. C'est surement la valeur finale que doit avoir notre mot de passe.

      Ensuite vient un appel de la fonction printf qui prend comme argument la chaîne "Crackme pour info...", et va l'afficher dans la console.

      Une adresse est placée dans le registre EAX puis passée en paramètre à la fonction scanf. Le 2ième paramètre ("%d") indique que la valeur récupérée sera au format numérique entier. Cette fonction récupère les caractères saisis au clavier et les place dans une variable (voir cours de C). C'est à dire que le mot de passe que l'on va taper sera stocké à l'adresse [valeur de EBP - 14].

      La 2ième variable déclarée ( j ) est placée dans EAX puis multipliée par la 1ère ( i ). On a donc l'opération EAX = 0 * 1 = 0. Le résultat est déplacé dans EDX puis notre mot de passe lui est ajouté. Attention, toutes les valeurs numériques sont exprimées en hexadécimal. Par exemple, si notre mot de passe est "123456", en hexadécimal, il devient 1E240 (noté 0x1E240 en C). A ce moment, EDX contient donc notre pass.

      L'instruction suivante effectue en fait 2 opérations: ajouter 2 à la valeur contenue dans EDX (notre pass) et déplacer le résultat dans EAX. Ce nombre est ensuite écrit à l'adresse [EBP - 10] que l'on va définir comme étant la variable "temp".

      La 4ième instruction de cette partie (LEA ESI...) n'est jamais exécutée car les 2 sauts (JNZ et JMP) lui passe dessus, donc on s'en fout! Les 3 autres instructions servent à la gestion de la boucle. Une comparaison est faite entre la variable j et la valeur 3. Ce qui indique que la boucle sera exécutée 3 fois. Le saut du JNZ sera effectué jusqu'à ce que le compteur soit égal à 3. A ce moment, le JMP nous fera sortir de la boucle.

      D'abord, notre variable temp est placée dans EAX pour lui ajouter 2. Ensuite, on place j dans EDX pour le multiplier par i. EDX est transféré dans ECX pour lui ajouter notre pass. On a donc EAX = temp + 2 et ECX = pass + i * j. Ces 2 valeurs sont aditionnées, puis le résultat est placé dans EDX. La valeur finale est enfin copiée dans notre variable temp.

      Le compteur de la boucle, j, est incrémenté ainsi que la variable i. Ensuite, le JMP nous renvoit au début de la boucle pour une nouvelle itération.
      Voici les opérations effectuées sur notre pass à ce stade:

temp = pass + 0 * 1 + 2 + pass + 0 * 1 + 2.
Les variables i et j étant incrémentées à chaque passage dans la boucle, nous ajouterons à la formule précédente, au second passage (i et j valant respectivement 1 et 2):
pass + 1 * 2 + 2
Puis au 3ième passage, avec i = 2 et j = 3
pass + 2 * 3 + 2

      Finalement, le résultat de tous ces calculs est placé dans EAX pour être comparé à la valeur 0x1A05A88 déclarée en début de routine. Si ces 2 valeurs sont différentes, le JNZ saute sur la fonction printf qui affiche "Mauvais pass...", sinon la fonction printf affiche "Bonne reponse..." puis le JMP saute vers la fonction system qui permet au programme d'attendre que l'utilisateur appuie sur une touche avant de quitter.
      Maintenant que l'on sait ce que fait le programme, nous allons reprendre les 3 formules pour les simplifier. Au final, on obtient la formule suivante:

temp = pass + 0 * 1 + 2 + pass + 0 * 1 + 2 + pass + 1 * 2 + 2 + pass + 2 * 3 + 2

On peut simplifier de la façon suivante:

0x1A05A88 = 4 * pass + 16

Donc on sort la calculatrice et on obtient le bon mot de passe! (0x1A05A88 = 27286152)

pass = (27286152 - 16) / 4 = 6821534

Kharneth 

All the children are insane
Waiting for the summer rain, yeah


Merci à toutes les personnes qui se battent pour que l'Information soit accessible à tous!