Cours n°4 - Patching & Reverse Engineering

 

        Ce dont vous avez besoin : Olly, ResHacker, CAscii et le même crackme qu' au cours précédent : FishMe1

       

        Comme l'analyse du logiciel, l'observation et l'analyse du code ont déjà été faites au cours précédent, pas besoin des les refaire ici.

 

Patching

    On va enfin s'amuser :D.

    ¤ Utiliser ResHacker

    Imaginons qu'on n'ait pas pris le temps de faire toute l'analyse que l'on vient de faire dans le cours précédent (il y a des gens paresseux ;) ), dans ce cas, prenons ResHacker. Grâce à ce logiciel, nous allons pouvoir modifier les ressources de notre exécutable.

    Faites File>Open et ouvrez le crackme ou faites un glisser déposer.

    Il n'y a qu'une ressource dans l'arborescence Ouvrez l'arborescence jusqu'au bout et cliquez sur 1033. Une fenêtre s'ouvre en affichant notre fenêtre du crackme. Faites un clic droit sur le bouton "Vérifier !">Edit control et chercher dans la nouvelle fenêtre la valeur WS_DISABLED qui doit être en jaune.

    Cliquez dessus pour l'afficher en gris, puis OK.

    Ensuite appuyez sur Compile Script.

    Maintenant fermez ResHacker et enregistrez lorsqu'il vous le propose (n'oubliez pas l'extension ".exe" si vous n'enregistrez pas sur l'ancien exécutable).

    Si vous lancez l'exe, vous pourrez maintenant cliquer sur "Vérifier !", mais il suffit de changer la valeur dans la zone de texte pour que ça ne fonctionne plus!

 

    ¤ Patcher bêtement

    Les façons de faire sont quasi infinies. Voici un exemple (en rouge ce qui a été patché) en modifiant un saut afin que l'on saute toujours vers la routine qui active le bouton:

    Voici un autre exemple où j'ai modifié la routine qui désactive le bouton afin qu'elle l'active:

 

Reverse Engineering

    Je définirais le Reverse Engineering comme ceci : "C'est l'action de modifier un programme afin qu'il fasse une chose pour laquelle il n'avait pas été programmé au départ".

    Je ne sais pas si c'est réellement du RE que nous faisons ici, mais nous allons modifier le programme afin qu'il écrive dans la zone de texte le bon serial lorsque l'on s'est trompé.

    Ce qu'il nous faut pour cela, c'est une fonction qui écrit du texte dans un contrôle. Nous en avons une : SetDlgItemTextA qui sert à définir le caption du label.

    Cette API demande 3 paramètres : l'adresse du texte (on l'a), l'ID du controle (on va le trouver) et l'hWnd (on l'a aussi).

    Pour trouver l'ID du controle (la zone de texte), reprenons ResHacker. Ouvrez l'exe et cliquez sur la zone de texte. Une petite '*' rouge doit se trouver devant la ligne correspondant à celle-ci.

    Le numéro qui suit le CONTROL "" est l'ID de la zone de texte, c'est-à-dire 201. Mais celui-ci est en décimal, alors que dans Olly il est en hexa.

    Lancez CAscii, dans Code Ascii(=decimal) tapez 201 et appuyez sur ENTER. La valeur en hexa correspondante est donc 0C9h (on aurait pu le deviner en regardant la fonction GetDlgITemText).

    Nous avons tout ce qu'il nous faut. Maintenant il faut trouver de la place pour mettre cela.

    Logiquement on veut que ce code soit exécuté lorsque l'on a tapé un mauvais serial, on peut donc le mettre à la place du EnableWindow, ... FALSE. Mais nous n'aurons pas assez de place. On va donc regarder dans les bytes libres à la fin de l'exe, là-bas on aura largement la place.

    Placer vous sur une ligne libre.

    La première chose à faire est de pousser les paramètres :

    1) L'adresse du texte : tapez PUSH 403000 (C'est l'adresse du bon serial qu'on avait trouvée tantôt)

    2) L'ID du control : tapez PUSH 0C9 (LE 0 devant est obligatoire)

    3) hWnd on le retrouve un peu partout, il est enregistré en [EBP+8] : tapez PUSH [EBP+8]

    Ensuite L'appel à la fonction :

    4) L'appel à la fonction : tapez CALL SetDlgItemTextA (respectez la casse)

    Et enfin le retour :

    5) Après avoir exécuté ceci il faut retourner quelque part, nous voyons qu'après le CALL EnableWindow,...,FALSE on sautait en 4010EE, puisqu'on ne doit plus exécuter cette fonction (EnableWindow,...,FALSE) autant sauter directement en 4010EE: tapez JMP 4010EE.

    Après ces manipulations vous devez avoir ceci (la ligne à laquelle vous avez commencé à taper peut être différente) :

    C'est presque fini. Notre code est défini mais rien ne l'appelle encore! A la place du premier paramètre du CALL EnableWindow,...,FALSE (PUSH 1 en 004010D2) tapez JMP 0040116C (ou une autre adresse si vous avez placé votre code un peu plus bas ou un peu plus haut que moi).

    Et voilà, maintenant la zone de texte affichera toujours le bon serial! :D

 

    Mais cette méthode ne me convient pas entièrement. La zone de texte est "bloquée", même si le bon message est toujours affiché dedans.

    Voici un autre exemple ou le Reverse Engineering prend encore plus de sens.

    Nous allons ajouter un bouton qui mettra le bon serial dans la zone de texte lorsqu'on on cliquera dessus.

    Prenez ResHacker, ouvrez le crackme, faite un clic droit sur la fenêtre représentant l'apparence du crackme et sélectionnez "Insert control". Dans la fenêtre qui s'est ouverte, cliquez sur l'icône représentant un bouton. Dans la zone de texte "Caption" entrez le texte que vous désirez voir apparaître sur votre nouveau bouton. Dans la zone "ID", entrez un numéro encore non utilisé, 203 par exemple. Lorsque c'est fait, cliquez sur "OK". Redimensionnez ensuite votre bouton et placez le à votre convenance. Cliquez sur "Compile Script", fermez ResHack et enregistrez.

    Vous venez d'ajouter un bouton mais si vous exécutez votre nouveau crackme, lorsque vous cliquez dessus il ne se passe rien! Normal, on ne lui a pas encore associé de code.

    Prenez la source que je vous avais fournie déjà au cours précédent et regardez un peu la structure de test d'appui sur un bouton :

    .ELSEIF uMsg == WM_COMMAND  
        mov eax, wParam                 
        mov edx, wParam
        shr edx,16         
        .IF dx==BN_CLICKED

            .IF ax == IDC_BTNOK               ;Si on a cliqué sur le bouton OK              
                INVOKE GetDlgItemText,hWnd,IDC_EDT1,ADDR strBuffer,cTAILLEBUFF              
                INVOKE MessageBox, hWnd, ADDR strBuffer,ADDR strTitle,MB_OK
            .ENDIF
        .ENDIF
    .ELSEIF uMsg == WM_CLOSE

    Ce qu'il faut c'est rajouter un test dans BN_CLICKED pour ax==203 (l'ID de notre bouton). Mais comment savoir ou le mettre?

    Voici comment elle est traduite par le compilateur (il suffit de repérer les 2 fonctions GetDlgItemText et MessageBox pour trouver) :

   

    On peut donc déduire que la constante WM_COMMAND est traduite par 111, BN_CLICKED est traduit par 0 ( OR DX,DX = test si égal à 0) et IDC_BTNOK par 0CA (on aurait pu savoir celui-ci en regardant avec ResHacker l'ID du bouton "OK")

    Ouvrez avec Olly le crackme modifié. On va rechercher cette structure dans notre crackme. On sait déjà que cette procédure doit se trouver dans la procédure associée à la dialogbox, donc pas besoin de chercher ailleurs.

    On retrouve les 3 nombres dans le même ordre (entourés). Je ne sais pas si les flèches vous aiderons mais bon ;)

    Voilà donc les étapes avant d'arriver au bouton : on teste si WM_COMMAND (111h) si oui, on retravaille wParam ( [EBP+10h] ), on teste si dx==BN_CLICKED (0) et enfin on teste si ax==BOUTONOK (0CAh), si ax!=BOUTONOK on saute en 0040110B, si ax==BOUTONOK, lorsqu'on a éxécuté la routine associée au bouton, on saute en 0040110B également.

    Nous devons donc sauter en 0040110B après avoir éxécuté la routine de notre bouton. Mais où placer le test de notre bouton? Simplement en dessous de CMP AX,0CAh, à la place de sauter vers 0040110B, on va sauter vers notre bouton.

    Pour l'écriture de notre bouton 2 solutions sont possibles, soit on teste si l'ID correspond bien à notre bouton, soit on se dit que comme il n'y a que 2 boutons, si le code envoyé n'est pas celui de BOUTONOK, ça ne peut-être que celui que l'on vient de rajouter.

    Par soucis de "propreté", j'écrirai un test de l'ID de notre bouton avant d'exécuter la routine qui copiera le bon serial, on n'est jamais trop prudent.

    Comme la dernière fois, cherchons de la place à la fin de l'exe.

 

    Placez vous sur une ligne vide et voici ce que vous devez faire :

    ¤ Test de l'ID

    Prenez CAscii, tapez l'ID de notre nouveau bouton (203) dans Code Ascii(=décimal), appuyez sur Entrer. L'ID en hexa de notre bouton est donc CBh. En assembleur, une valeur ne peut pas commencer par une lettre, il faut donc placer un '0' devant ce qui donne 0CBh.

    1) Il faut donc tester si l'ID qui se trouve dans AX est bien 0CBh : tapez CMP AX,0CBh

    2) Si ce n'est pas égal il faut sauter vers la suite, donc 0040110B (rappelez-vous c'était là que l'on sautait si AX n'etait pas égal à l'ID du bouton OK) : tapez JNE 0040110B

    ¤ Copier le bon serial dans la zone de texte

    C'est exactement le même code qu'ici au dessus :

    PUSH 403000

    PUSH 0C9

    PUSH [EBP+8]

    CALL SetDlgItemTextA

    ¤ Retourner à la suite

    Il faut retourner à la suite, c'est donc encore la même adresse à savoir 0040110B : tapez JMP 0040110B

 

    Il reste encore une petite chose avant de terminer, tout est défini mais on n'arrive jamais à cette routine vu que l'on a pas encore changé le CMP AX,ID_BOUTONOK

JNZ 0040110B                     en    JNZ 0040116C (l'adresse du début de notre nouvelle routine de test que l'on vient d'écrire, ca peut différer selon la ligne où vous avez commencé)

    Allez à la ligne du JNZ 0040110B (0040107C) et tapez JNZ 0040116C.

    Testez! Si ça fonctionne bien, faites un clic droit>Copy to executable>all modifications fermez la fenêtre qui s'ouvre et enregistrez.

 

 

Bon crack,                  

Crisanar         

[ << Cours n°3 ] [ Cours n°5 >> ]

 

Dernière mise à jour le 30/09/2004 21:12