Tutorial pour le U4N1 de Kharneth
Outil nécessaire:
Niveau: débutant ayant des bases en programmation et unpacking I. IntroCe programme, comme nous l'a dit Kharneth, est destiner a être unpacké. Nous allons suivre les étapes indiquées par l'auteur dans son readme. Je vais considérer que vous avez déjà certaine notion en ce qui concerne l'unpacking et le format PE.
II. Dump fonctionnelBien, tout d'abors, on va collecter des infos sur la bêtes histoire de pas partir en l'aveugle. Ouvrez la donc avec LordPE et on note ces différents éléments: entry point: 61BC image base: 400000 import table: RVA= 6010 ; Size= 28 (en hexa) On note aussi qu'il y a trois sections:
Bien maintenant chargeons le programme dans olly. On arrive donc a l'entry point, et on voit une "grande boucle" (sans doute le loader), et à la fin de celle-ci, des instructions ma foi forte tape-à-l'oeil: on met tout les registres 32bits en bas de la pile, puis on retourne en 401000. Interressant non ? Ca ne ferait pas penser à un JMP OEP ? Et bien si justement ! C'est à cet endroit que l'on va retourner à l' OEP. Posons donc un bp sur le RETN, faites F9 pour lancer le programme, enlevons le breakpoint et appuyons sur F8. Et hop, on est bien en 41000 ! On va donc dumper a cet endroit. Pour cela, on peut utiliser le plugin Ollydump: Plugins => Ollydump => dump debugged process (décochez bien la case "Rebuild Import" !):
Nommez le dump de la manière qu'il vous plait. Moi histoire de faire original je l'ai appelé "dump". Ceci fait, il ne reste plus qu'à lancer le programme originel et à sortir imprec. Dedans, selectionez le crackme de Kharneth, changez l'oep en 1000 et cliquez sur "IAT Auto Search". Le programme nous dit qu'il a bien trouvé l' IAT, on peut donc cliquer sur "Get Import", puis, comme il n'y a aucun problème, sur "Fix Dump" et allez chercher votre dump. Voila ce n'était pas bien compliqué, comme vous le voyer, d'obtenir un dump valide avec quelques outils. III. Analyse du loaderLe loader est situé à l'entry point + image base, c'est a dire en 004061BC. C'est a cet endroit qu'on tombe quand on charge le crackme dans olly. On peut découper le loader en 3 parties: la décompression des sections, la résolution des imports, et le retour à l' OEP. La première partie est celle-ci:
Dans cette partie, on voit rapidement que le programme récupère l'image base pour la stocker dans une variable. La boucle sert à décompresser les sections en mémoire. Le CALL 00406078 appelle la fonction de décompression de l'aplib. Comme l'analyse de cette fonction n'est pas demander, nous allons nous en passer. Pour les plus courageux, je vous invite à lire le tuto très détaillé de Beatrix sur FSG ( le lien est donné par Kharneth dans la consigne). Une fois toute les sections décompressées, le programme quitte la boucle (je suis relativement bref car j'ai pris soin de détailler le code). La seconde partie est comme je l'ai dit, destiné à la résolution des imports. Analysons chaques passages:
Comme précédement, j'ai essayé de commenter le code du mieux possible, je ne m'attarderais donc pas trop sur cette boucle. Ce que l'on doit retenir, c'est qu' il place, pour chacunes des dll, les adresses des fonctions chargés en mémoire dans le FirstThunk. Les adresses des fonctions chargés en MEMOIRE !! C'est pour cela qu'elle sont de la forme 77XXXXXX. Un autre point relativement important pour la suite. C'est en 00406241 qu'il faut aller. Le ADD EBX,14 nous fait passer à la dll suivante, et on place dans EBX l'adresse d'un pointeur vers la première api de la dll suivante, et la ligne suivante: MOV EAX,DWORD PTR DS:[EBX+C] place l'adresse du nom de la dll dans eax... La taille de 14h, le pointeur vers un pointeur, l'adresse du nom de la dll... Je vous laisse réfléchir dessus, nous y reviendrons au IV. Ensuite après avoir décompressé toute les sections, traité chaques dll, on peu tranquillement retourner à l' OEP via le RETN:
Voila pour l'analyse du loader !
IV. Dump avec reconstruction manuel de l' Import TableBien, le but maintenant est de faire comme dans le II, mais sans imprec :). Nous allons proceder de la manière qui suis: il faut d'abors voir l'ordre dans lequel les api sont appelées, repérer les adresses de celle-ci dans le dump, corriger l'import table et l'iat. Refaites un donc un dump du programme (de la même facon que dans le II. ) que vous nommerez dumpM Nous allons donc tout d'abors regarder dans quel ordre les api sont appelées. Pour ce faire prenez olly et l'exe original, puis dans la boucle de résolution des imports, notez, pour chaque dll, l'ordre d'appel des api. Ceci est très important car si on ne respecte pas cet ordre, le programme, au lieu par exemple d'appeler GetWindowTextA, va appeler une autre api (coucou TTO :) ). Bref vous voyez le désordre !! Donc je suppose que vous l'avez fais, vous devriez logiquement obtenir: pour user32.dll:
Pour kernel32.dll:
Pour gdi32.dll:
Pour msimg32.dll:
Bien, ceci fait, on va maintenant regarder les adresses de ces imports dans notre dumpM. Pour ce faire, ouvrons le dans un éditeur hexadécimal et rendons nous la ou se situe les api. Elles commencent en 0x41F4. Tout ce qui se situe avant c'est simplement l' iat. Bon je vous laisse le soin de faire ce travail relativement long. Bien, maintenant occupons nous de l'import table. LordPE nous indique qu'elle se situe en 6010 et que sa taille vaut 0x28. Quand on va à cet endroit, que voit-on ? ceci:
On tombe en fait sur l'import table du loader ! Et si vous regardez les adresses commençant en 6000, elles ressemblent fort a des adresses de fonction en mémoire (si vous voulez vérifier, utilisez GPA en prennant l'une des apis), et même des fonctions présentes juste en dessous. On ne va donc pas se gêner, et remplacer l'import table du loader par la notre. Je vais cependant faire une petite parenthèse. Dans notre import table, il y a autant d' IMAGE_IMPORT_DESCRIPTOR qu'il y a de dll utilisé (plus 1 vide la fin). Et le dernier dword contient le RVA du FirstThunk. Nous devons donc déterniner ces RVA. Remontons donc au lieu ou l'on à croisé les api, et remontont encore un peu, en 0x4000: Les valeurs que l'ont a ici sont comme tout à l'heure pour le loader, les adresses des fonctions chargées en mémoire. Maintenant pour savoir à quelle dll appartiennent ces blocs, nous allons utiliser GPA. Après avoir cherché, je trouve ceci:
Bon, fin de la parenthèse, retournons à notre import table. Maintenant qu'on a toutes les données, c'est vraiment simple. Nous allons remplacer les valeurs de l'import table qui servait au loader, pour mettre les notres. Le tableau ci dessus contient tout, et je vais supposer que vous connaissez la structure d'un IMAGE_IMPORT_DESCRIPTOR. Vous devez obtenir ceci (par souci d'esthétique, j'ai remplacé les "restes" des fonctions par des 0): Faisons tout de suite les changements dans l'optional header. En 0x38, remplacez le BaseOfCode par 0x1000, en 0x90, remplacer le 0x28 par 0x50. Passons maintenant à la correction de l'iat. Vous avez noté tout à l'heure l'adresse des fonctions (je vous rappelles en passant que ce vous avez noter était les adresses en "dur". Mais comme vous avez fait un dump en mémoire, ces valeurs coïncident désormait !! C'est pour cela que l'on va pouvoir les utiliser. Cool non ? ). et vous savez à quel dll appartiennent les blocs et enfin, vous avez l'ordre des imports... Bref vous avez TOUT pour remplir cet iat :p. A la fin de votre travail, vous devez obtenir ceci:
Enregistrez toutes vos modifications, et si vous n'avez fait aucune erreur de saisie, votre dumpM devrait fonctionner normalement !! Mais cette méthode est longue, et, il faut le dire, relativement chiante (oui bon j'avoue, c'est ce que j'ai fait en premier...). Il y a une autre méthode bien plus rapide ! Et oui, on peut aussi faire d'une manière qui ne prend pas plus de 15sec (Kharneth me disait 5sec, mais à croire que je suis long :D ). On peut se borner à 3 modifications !! Comme j'ai essayer de vous l'amener dans la partie précédente, le programme initialise tout simplement une import table en 0x40C8, et elle correspond bien a nos imports juste en dessous (on remarque que les FirstThunk sont mauvais, mais cela n'a pas une grande importance car les OriginalFirstThunk sont justes, et c'est ceux-ci que windows regarde en premier). Le modification a faire sont donc pour l'import table: changez l'adresse et la taille ( 50h ) dans l'optional header. Il faut aussi changer le BaseOfCode car notre permière section commence en 1000. V. Purge du dumpDans cette partie, nous allons essayer de supprimer toutes traces du loader dans le dump afin de nous rapprocher au maximal de l'exe original (consigne du créateur). Nous allons prendre pour cette partie une copie d'un de vos dump (ou faites en un autre si ca vous chante). Voici par quel méthode j'ai procédé (bon Kharneth t'es en première lecture donc après je supprimerais évidement cette parenthèse. Mais juste pour te dire que si j'ai mal fait ou mal compris le truc, engueule moi, mais avec des pincettes stp. Par ce que j'ai passé pas mal de temps a m'arracher les cheveux sur ton superbe packer): Kharneth dans un élan de générosité, nous donne le début de la section ressource dans l'exe original: 00460000. Si on soustrait l'image base a cette adresse, on obtiendra l'offset du début de la section dans le dump vu sous un éditeur hexa. Cette section commencerait donc en 6000. Mais a cette adresse se trouve déja quelquechose. Cependant, si vous remonter un peu dans ce tut, vous verrez que c'est juste un peu après, en 6010 que dans un élan de folie, j'avait coller mon import table. Et cela n'avait affecté en rien le fonctionnement du programme. Ceci m'a fait pensé que la partie allant de 6000 à 8000 ne servait pas. Je l'ai donc tout bonnement supprimée. J'ai ensuite parcouru le dump a la recherche de section "type" tel que .text , .data , .rdata ect... La section .rdata est très facile a trouver puisque c'est celle qui contient les imports. Ensuite, la section data est celle qui contient tout texte utilisé dans l'exe. J'ai donc regarder dans olly dans les SDR et par bonheur j'en ai trouvé une: "Pbatenghyngvbaf! :)". J'ai donc fait une recherche dans l'éditeur hexa à la recherche de cette chaine de caractère et on là trouve en 0x521F. Mais la section commence réellement en 0x5000. Ensuite la section .text contient le code du crackme. C'est aussi la première section... L'entry point du dump étant en 0x1000, notre section est trouvé ! Bien maintenant que toute les sections sont identifié, passons a la correction. Vous pouvez le faire manuellement sous l'éditeur hexa, mais en bon fénéant que je suis, j'ai décider de prendre LordPE. Je vous conseil de supprimer toute les sections existantes puis d'en recréer quatre. Je vais aller vite ici car tout est aisément trouvable sous l'éditeur hexa. Voici ce que vous devriez avoir: Ensuite, pour les sections: Et enfin: Si vous sauvez vos modifications et que vous lancez votre dum, vous verrez qu'il y a un problème. Il manque en effet un point: certaines chose doivent être modifier dans les ressources... Greetz Kharneth pour tout ce qu'il fait pour moi (me supporter entre autre, et c'est déjà beaucoup:D )! Kaine, elooo, Beatrix, Neitsa, Thierry_The_One, Kef et tout les autres ! Ceux qui me supporte et me soutienne.
You're all stare, But you'll never see, There is something inside me. |