Comment cracker un programme qui se ferme quelques

instants après son ouverture :

 

 

Tutorial écrit par: ThE_BuG87 (thebug87@caramail.com)

Niveau: débutant

Logiciel cible: Clavier2000 version d'évaluation(http://pdth.free.fr/Clavier2000.exe)

Outils nécessaires: WDasm v8.9, Un éditeur hexadécimal, la calculatrice de Window$,

                             un chrono, de la bonne musique, un cerveau

 
 

Introduction:

 

            Cela fait un bon bout de temps que je me suis lancé dans le cracking et ceci est mon premier tutorial, gros égoïste que je suis! Ainsi je vous demande d'éviter un tel comportement et de penser un peu aux autres, au moins aux développeurs qui méritent d'être encouragés et ceci en achetant leurs produits car tout ce que vous trouvez dans les tutorials comme

celui-ci reste à des fins pédagogiques.

      Enfin comme j'ai un peu muri depuis, je me suis décidé à commencer à faire part aux débutants du peu de connaissances que j'ai...Et cela en commançant par vous apprendre comment on peut se débarasser d'une simple protection qui vous oblige à réouvrir un programme qui se ferme automatiquement après 2 ou 3 minutes...Ceci est un tutorial pour les débutants donc

le programme que j'ai choisi est en fait simple et nous n'aurons besoin que d'un désassembleur et WDasm est vivement conseillé (donc pas de SoftIce and co...).

      J'ai failli oublier(c'est dur de faire des tut.), le logiciel cible vous apprend à taper vite au clavier (pour donner l'impression d'être un cracker), il se ferme 1min et demi après son ouverture, faisons en sorte qu'il se ferme après 40 jours...(pourquoi 40 jours? vous verrez plus tard). Tâchez de vous le procurer avant de continuer à l re mon cours! (Ca

sonne si bien...:). Voici l'URL: "http://pdth.free.fr/Clavier2000.exe".

 

I - Go, go, go: on désassemble:

 

            On se lance donc. On commence par ouvrir notre WDasm, on clique sur Disassembler/Open File to Disassemble.. puis on sélectionne notre fichier exe (normalement "Clavier.exe"), nous obtenons ainsi notre beau dead listing qui a l'air cohérent et contenant les string references ...etc... Il n'est donc pas compressé ou crypté! On peu ainsi directement se plonger dans le code.

      On commence par rechercher dans les strings references le message fermant notre application mais cela ne nous donne pas grand chose car nous ne savons pas exactement ou cette partie du code a été appelée:

 

:004570AF 61                         popad

:004570B0 6C                         insb

:004570B1 000000                  BYTE  3 DUP(0)

 

* Possible StringData Ref from Code Obj ->"Envoyez-moi un mail avoir des "

                                        ->"infos sur la version compl"

                                  |

:004570B4 B8CC704500                    mov eax, 004570CC    <== surement un appel ici mais à partir

:004570B9 E892D5FDFF                   call 00434650                          d'où???????

:004570BE E899C6FAFF                   call 0040375C

:004570C3 C3                                     ret

 

C'est un appel indirect (passant par un registre par exemple...) et qui n'a pas de raison d'apparaître d ns notre dead listing. Ce n'est donc pas la bonne voie, let's try something else (c'est d'l'anglais) (-->Cela veut dire que nous essayerons autre chose pour les anglophobes!)

      Tout d'abord je vous présente une API qui s'avère intéressante dans notre cas, il s'agit de SetTimer de la librairie User32.dll. Voici sa définition (d'après Win32.hlp, une référence que je conseille "violemment" comme dirait mon prof de Physique):

UINT SetTimer(

 

    HWND  hwnd,         // handle of window for timer messages

    UINT  idTimer,        // timer identifier

    UINT  uTimeout,      // time-out value

    TIMERPROC  tmprc           // address of timer procedure

   );

 

            Mais que fait cette fameuse fonction? C'est simple, elle crée un Timer, en d'autres termes, elle amorce un compte à rebours dont la valeur initiale est précisée grace à l'argument uTimeout (en millisecondes) et une fois le compte à 0, la procédure dont l'adresse st donnée par tmprc est exécutée.

      Ceci étant dit, je vous propose donc d'exécuter notre logiciel et d'attendre 90 secondes. Là, vous ne pouvez plus utiliser le logiciel (dommage il était intéressant le cours de philo) et un message vous demandant de contacter l'auteur pour la version complète apparaît, cliquez sur OK, le programme se ferme. Vous avez donc tout de suite perçu la relation qui existe entre ce que fait notre logiciel et SetTimer, sinon, et bien au lancement du programme on pourrait supposer que celui-ci fait appe à cette API en lui passant dans uTimeout une valeur proche de 90000 car on sait que le programme se ferme après une minute et demi (si vous n'en n'êtes pas sûrs, chronometrez! Attention ne commencez le chrono qu'après avoir fermé la fenêtre de présentation en cliquant dessus) soit donc 90000 millisecondes = 90 secondes = 1 minute et demi, et dans tmpr, l'adresse à laquelle sont contenues les instructions relatives à l'affichage de la fenêtre vous obligeant à fermer le programme. Mais ceci est une simple intuition (principale qualité du cracker!). Verifions si elle est valable!...  

      On s'empare donc de notre WDasm avec notre fichier préalablement ouvert, on ouvre la fenêtre relative aux fonctions importées (soit Functions/Import soit directement grâce au bouton de raccourci) puis on cherche calmement notre user32.SetTimer. Vous pouvez aussi directement cliquer sur Search/Find Text puis taper "SetTimer" ce qui est parfois plus rapide. Quelle que soit la méthode choisie vous remarquez que "SetTimer apparaît 5 fois dans notre dead listing (il faudra négliger la première référence obtenue grâce à la seconde méthode et qui fait partie juste de la présentation des fonctions importées et dont Se Timer fait partie):

 

--------------------1ère occurence:-------------------

 

* Referenced by a CALL at Addresses:

|:0042E502   , :00433D7B   , :0044CDF5   , :004576D0  

|

 

* Reference To: user32.SetTimer, Ord:0000h

                                  |

:00405C78 FF2530544600                 Jmp dword ptr [00465430]

:00405C7E 8BC0                                mov eax, eax

 

--------------------2ème occurence:-------------------

 

:0042E4F8 6800CA4200                    push 0042CA0

:0042E4FD 56                                     push esi

:0042E4FE 6A00                                 push 00000000

:0042E500 6A00                                 push 00000000

 

* Reference To: user32.SetTimer, Ord:0000h

                                  |

:0042E502 E87177FDFF                    Call 00405C78

 

--------------------3ème occurence:-------------------</ pan>

 

:00433D72 6A00                                 push 00000000

:00433D74 56                                      push esi

:00433D75 6A01                                 push 00000001

:00433D77 8B4328                             mov eax, dword ptr [ebx+28]

:00433D7A 50                                     push eax

 

* Reference To: user32.SetTimer, Ord:0000h

                                  |

:00433D7B E8F81EFDFF                   Call 00405C78

 

--------------------4ème occurence:-------------------

 

:0044CDE4 6A00                                push 00000000

:0044CDE6 6890010000                     push 00000190

:0044CDEB 6A01                               push 00000001

:0044CDED 8BC3                               mov eax, ebx

:0044C EF E8AC51FDFF                 call 00421FA0

:0044CDF4 50                                     push eax

 

* Reference To: user32.SetTimer, Ord:0000h

                                  |

:0044CDF5 E87E8EFBFF                   Call 00405C78

 

-------------5ème et dernière occurence:--------------

 

:004576C7 6A00                                 /span>push 00000000

:004576C9 56                                      push esi

:004576CA 6A01                                push 00000001

:004576CC 8B4334                            mov eax, dword ptr [ebx+34]

:004 76CF 50                                     push eax

 

* Reference To: user32.SetTimer, Ord:0000h

                                  |

:004576D0 E8A3E5FAFF                   Cal 00405C78

 

            On peut déjà faire une remarque importante concernant la première occurence de SetTimer: on observe que le "Jmp dword ptr [00465430]" est appelé par 4 CALLs différents ::0042E502   , :00433D7B   </ pan>, :0044CDF5   , :004576D0, si vous analysez les adresses de ceux-ci vous vous apercevez qu'elles correspondent exactement aux 4 autres occurrences (et ce n’est pas pour rien que j’ai mis des couleurs !). En fait notre "Jmp dword ptr [00465430]" est la vrai référence à SetTimer et si vous portez votre attention sur le code qu'il y a autour, vous remarquez qu'il n'y a que des jmp du même type, chacun appelant une API différente. Il s'agit là de toute une table de références aux APIs. Donc pour appeler une API dans le programme, notre call ne fera pas directement référence à celle-ci mais passera par la fameuse table. Malgré cela et heureusement d'ailleurs, WDasm déte te le call comme faisant référence à l'API (Po mal non?). C'est le cas de nos 4 CALLs.

 

II - Utilisation du debugger de WDasm:

 

            Vous allez me dire que tout ce que je vous ai appris à propos de SetTimer est bien intéressant mais comment je sais que cette fonction est bien appelée au début du programme et que c'est elle que notre programme utilise afin de nous chronometrer. Vous avez raison, prouvons-le!

      Nous allons pour cela utiliser le debugger de WDasm (pas très puissant mais peut faire l'affaire dans notre cas). Ouvrez donc notre ex cutable avec WDasm si ce n'est pas déjà fait puis cliquez sur Debug/Load Process ou tout simplement faites Ctrl+L, notre programme est maintenant chargé en mémoire et prêt à être exécuté. Pour poser un breakpoint au niveau d'une instruction précise (c'est à dire faire en sorte que programme s'arrête une fois cette instruction atteinte), il suffit de la selectionner de façon à ce qu'elle soit en bleu dans la fenêtre principale de WDasm (celle contenant le dead listing). Attention! Les breakpoints ne peuvent être posés que si le programme est chargé en mémoire. Donc une fois l'instruction selectionnée, appuyez sur F2 ou cliquez sur Debug/Breakpoint Toggle. Maintenant vous pouvez lancer votre programme en cliquant sur le bo ton "Run" qui figure dans la fenêtre du debugger qui apparaît généralement à droite, et une fois arrivé à l'instruction ou l'on a posé notre breakpoint, WDasm nous donne la main avant de l'exécuter.

      Revenons à notre programme! Nous étions en train de chercher à prouver que c'est bien SetTimer qui est responsable de la maudite protection. On sait d'après le dernier paragraphe de la partie précédente que si SetTimer s'exécute dans notre application, alors l'instruction "Jmp dword ptr [00465430]" est forcémen exécutée, mettons donc un breakpoint à son adresse soit à 00405C78 et exécutons le programme. Cliquons sur la fenêtre de présentation, et là, ça break (ça s'arrête). Donc on peut supposer que le compte à rebours commence une fois que l'on a cliqué sur la fenêtre de présentation.

      Bien, nous venons juste de prouver que SetTimer est appelée et non pas que l'usage qui en est fait est celui que nous espérons. Pour cela, voyons lequel de nos 4 CALLs fait référence à SetTimer au début du programme, nous aurons sûrement plus d'info . On clique donc sur le bouton "Terminate" qui existe dans la même fenêtre que le bouton "Run" (voir précédemment). Le programme n'est plus chargé en mémoire et notre breakpoint n'existe plus. OK! Rechargeons le avec Ctrl+L et cette fois-ci posons 4 breakpoints, chacun sur un de nos CALLs. Mettons "Run" et le programme break sur notre second CALL, les autres ne nous intéressent plus désormais.

      Analysons donc ce CALL, et surtout ses paramètres, (jetez encore un coup d'oeil sur la définition de SetTi er), je rappelle que les paramètres en assembleur sont passés dans l'ordre inverse de celui correspondant à leur définition:

  

:00433D72 6A00                    push 0000 000                        <== tmprc : ne nous intéresse pas

:00433D74 56                          push esi                                    <== uTimeout : Tiens, tiens!

:00433D75 6A01                    push 00000001                        <==idTimer: inintéressant

:00433D77 8B4328                 mov eax, dword ptr [ebx+28]

:00433D7A 50                         push eax                                   <== inintéressant

 

Reference To: user32.SetTimer, Ord:0000h

                                  |

:00433D7B E8F81EFDFF              Call 00405C78

 

            Au moment ou WDasm break sur notre call, on analyse le contenu des registres (voir l'autre fenêtre d debugger que celle contenat les boutons "Run" et "Terminate") et en particulier le registre esi car c'est lui qui contient la valeur de l'argument uTimeout, c'est à dire la valeur initiale du compte à rebours. On voit que esi = 15F90h soit esi = 90000d.

Vérifiez en utilisant la calculatrice de Windows, mettez vous en mode scientifique, en hexadécimal (Cochez "Hex"), tapez 15F90 puis mettez vous en mode décimal (Cochez "Dec"). BINGO! Tout notre raisonnement est juste. Le compte à rebours est initialisé à 90000 millisecondes soit une minute et demi. Notre application utilise bien SetTimer pour limiter l'utilisation du logiciel à cette durée. Nous allons donc modifier le code de ce programme mais comment? Je propose de remplacer push esi par push <une énorme valeur>. Nous ne pouvons pas spécifier une valeur de notre choix car "push esi" est codée sur un seul octet, on est obligé de passer par un registre. On a remarqué, en jetant un coup d'oeuil sur les registres tout à l'heure, que la valeur de ecx était assez grande, ecx = CFA62C10h = 3483773968d. Or, 3483773968 millisecondes = 3483773.968 secondes = environ 967 heures = environ 40 jours. Si nous remplaçons notre "push esi" par "push ecx", le programme s'arrête a 40 jours après son lancement ce qui est à mon avis un peu mieux que 1 minute et demi, et ce qui s'avère largement suffisant à moins que vous ne soyez accros du clavier::).         

    

III - Patcher le programme:

 

            Le fait de remplacer une instruction par une autre s'appelle "patcher" cette instruction ou encore "patcher" l'application quand vous la modifiez en disque dur. Je vais donc vous montrer comment utiliser WDasm pour patcher (Que ferait-on sans lui...). Chargez le programme en mémoire et mettez un breakpoint au niveau de "push esi" soit à l'adresse 00433D75 (vous savez comment faire maintenant!). Lancez l'application (bouton "Run"), cliquez s r l'écran de présentation de clavier 2000, à ce stade WDasm break là où nous lui avons demandé. Tout est OK! Cliquez maintenant sur "Patch Code" (un peu au dessus de "Run"), une fenêtre s'ouvre vous donnant l'instruction en cours ainsi que son adresse et un peu plus bas vous devez taper la nouvelle instruction qui prendra la place de celle en cours. Tapez "push ecx" et faites Entrer, une ligne apparaît dans le "Code Patch Listing":

 

:00433D74 51                            push ecx

 

            L'adresse est celle de "push esi", l'équivalent de l'instruction en hexadécimal est 51, tout ce qu'il faudra faire donc est de remplacer dans le code le 56 de "push esi" en 51 de "push ecx". Vous comprenez certainement mieux pourquoi je ne pouvais pas entre un instruction du genre "push X" avec X une valeur de mon choix, c'est simplement du au fait qu'une telle instruction est codée sur plus d'un octet et on débordera sur la prochaine instruction ce qui risque de foutre le bazar dans toute la suite du code ==> risque de plantage du système.

      Appuyez donc ensuite sur "Apply Patch", et à ce stade vous avez modifié l'instruction en mémoire seulement et non pas dans le fichier exe, par conséquent dès que vous relancerez le programme une autre fois notre "pu h esi" se rechargera en mémoire comme si de rien n'était. Il nous faut donc l'adresse de l'instruction "push esi" dans le fichier Clavier.exe. Là encore WDasm nous propose une solution simple et rapide. Vous sélectionnez l'instruction (faites en sorte qu'elle soit mise en valeur, elle devient surlignée en bleu en général) et vous regardez en bas de la fenêtre de WDasm, au niveau de la barre d'état. Vers la fin vous devez voir @Offset 00033174h in File: Clavier.exe. L'adresse de notre instruction dans le fichier est, vous l'avez deviné, 00033174. Ouvrez donc votre fichier exe avec votre éditeur hexadécimal favoris (après avoir fermé WDasm qui verouille les fichiers qu'il ouvre, sauf si vous avez eu le bon re lexe de faire un copie du fichier...) puis allez à l'adresse de l'instruction à modifier, je la rappelle: 00033174. Moi, j'utilise UltraEdit v10.00c donc je clique sur Search/Goto Line/Page puis je rentre mon adresse précédée d'un "0x" indiquant qu'elle est en hexadécimal. Là vous tombez directement sur l'octet 56 que vous remplacez par 51. Vous enregistrez et le tour est joué! Ouvez Clavier.exe, il ne se ferme plus... Ouuff! Sacré boulot d'écrire un cours sur le cracking.

 

Conclusion:

           

Je voulais juste vous signaler que d'autres méthodes peuvent exister pour mettre en place la même protection que celle de Clavier2000. Allez, je vous laisse, amusez-vous bien!

 

            Si vous ne comprenez pas quoi que ce soit, contactez moi sur thebug87@caramail.com, et comme je ne suis pas un expert en cracking (on va dire que je suis un grand débutant en la matière), je demande à tout professionnel de me faire part de ses critiques ou de me corriger mes erreurs s'il y en a.

 

      Je tiens également à remercier Deamon d’avoir bien accepté de me publier ce tutorial ainsi que tout les crackers dont les tutoriaux m’ont été d’une grande utilité. Merci !

 

 

                                                Tutorial écrit par: ThE_BuG87 (e-mail: thebug87@caramail.com)