COURS N°1 : L’unpack d’UPX
Salut à tous ! Alors aujourd’hui on va faire du manual unpacking et on va s’attaquer au packer (qui n’a pas un but de protection, mais de compression, c’est pas grave, on apprend quand même !) UPX, le plus dur qui soit (ben quoi ? rhôoo, on peut rigoler un peu quand même !.....non ? bon……)
- Mais monsieur, comment on fait pour savoir si un programme est packé ?
- Et bien mon petit, en règle générale c’est pas bien compliqué ! Déjà tu auras sûrement aperçu que tu n’avais pas de SDR dans windasm, ce qui éveille déjà quelques soupçons ! Tu peux aussi utiliser un programme spécialement fait pour détecter avec quel packer ton fichier est packé ! Comme language 2000, FileInspector……Dans le cas d’upx on peut faire directement la recherche du mot UPX dans un éditeur héxadécimal, s’il y est…..vous devinez la suite !
Objectif du tutorial : Etre capable d’unpacker manuellement 99% des programmes packés avec upx
A savoir avant de commencer :
Le programme a été compressé par UPX, ce qui signifie qu’il devient illisible tant qu’il n’a pas été décompressé. Lorsque UPX compresse un fichier, il greffe à ce fichier ce qu’on appelle le LOADER, qui est donc responsable de la décompression du fichier.
Il modifie l’entry-point du programme (qui correspond à l’adresse où commence le programme) pour que ce soit le LOADER qui se charge en premier, décompressant le programme en mémoire qui devient lisible.
Les étapes de l’unpacking :
1)Le dump du
fichier
Un dump, c’est une étape consistant à copier partiellement ou tout un programme en mémoire
Comme expliqué ci-dessus, le loader se charge de décompresser le programme en mémoire, puis de l’exécuter. Lors de cette étape, nous allons copier ce qui se trouve en mémoire après l’action du LOADER, ce qui signifie que dans notre dump nous aurons (avec le LOADER) notre programme décompressé.
2)Recherche de l’OEP
OEP est l’abréviation de Original Entry Point, c’est à partir de cette ligne que le programme non packé va commencer. Lorsqu’un packer est présent, c’est le LOADER qui se chargera en premier, et qui va commander la décompression du fichiere.Après avoir décompressé, le LOADER va jumper vers l’OEP du programme, afin que celui-ci se lance normalement.
3) Correction du PE
Le PE contient certaines informations sur le fichier. L’information qui va nous intéresser avec UPX, c’est l’OEP, en effet, UPX modifie l’OEP d’origine pour le remplacer par celui de son LOADER, et comme maintenant nous avons le dump (c'est-à-dire un fichier .exe contenant entre autres le programme décompressé) il nous suffit de remplacer l’OEP du LOADER par celui du programme, pour qu’au lancement de celui-ci ce soit réellement le programme qui soit lancé et pas le LOADER, devenu inutile.
4)Reconstruction
de l’IAT
L’IAT c’est en fait la table des imports, grosso modo c’est un tableau qui récapitule les .dll utilisées par le programme, ainsi que leurs adresses et celles des fonctions utilisées.
Petite précision sur l’IAT : En réalité, l’IAT compte deux tableaux, et non pas un seul. Le premier tableau contient le nom des fonctions importées, et le deuxième contient la même chose :P
Donc au lancement du programme, celui-ci va regarder les noms des fonctions importées dans le 1er tableau et en déduire (grâce à certaines API) leurs adresses réelles et stockera tout ça dans le 2ème tableau (écrasant ainsi les données qu’il contenait). En général lorsqu’un fichier est packé, le packer supprime le premier tableau pour gagner de la place
Mais comment on fait alors pour trouver les adresses réelles ?
Ben en fait on utilise le 2ème tableau, puis on utilise les API pour obtenir les adresses réelles, qui se stockeront dans ce même tableau, écrasant donc ces données.
Et là vous me demandez : mais à quoi ça sert de reconstruire l’IAT d’un programme si ça peut marcher sans le premier ? Là on va réfléchir un peu ! J’ai donc dis tout à l’heure qu’un dump était une copie d’un programme tournant en mémoire, il y a rien qui fait tilt ? Faut tout vous dire ! lol ! Si le programme tourne en mémoire, c’est qu’il a déjà été exécuté, donc le tableau 2 contient les adresses réelles et plus le nom des fonctions ! et lorsqu’on va lancer notre dump, le prog va chercher le nom des fonctions et va se retrouver avec des adresses, alors il va pas comprendre et va planter ! C’est pour cela qu’on doit remettre le nom des fonctions importées. C’est clair maintenant ? Au pire vous relisez, c’est peut-être pas évident du premier coup.
Voilà pour les généralités, maintenant on s’attaque au crackme :
Alors le matériel nécessaire : On utilisera LordPE (pour moi ce sera LordPe Deluxe by Yoda, j’ai pas la version par contre) pour obtenir les infos sur le PE et pour dumper, Ollydbg (j’ai utilisé la 1.09d), et Imprec v1.6 FINAL (pour ne pas se casser le cul :P) et aussi le crackme, oui évidemment….
Encore une petite précision avant de commencer !
Je suis extrêmement débutant en terme de programmation, j’ai codé ce petit crackme vite fait et il est simple à niquer même sans l’unpacker (réponse dans les sdr, c’est pour vous dire). Donc voilà, j’ai juste fait ce petit fichier pour donner un objectif à ce tut, juste histoire de balancer un programme qui afficherait juste qu’on l’unpacke. Voilà, maintenant c’est parti !
Nous allons respecter les étapes citées précédemment :
1)Le dump du
fichier
Donc là on va se servir de OllyDBG, je pars du principe que vous savez un peu l’utiliser. L’objectif de cette partie sera de trouver l’OEP du programme original, et de savoir quand le LOADER aura fini de décompresser le programme. C’est à ce moment là qu’on aura le programme décompressé en mémoire.
Alors, où est-ce qu’on va trouver ce qu’on cherche ?
- Dans le listing ? murmura une petite voix au fond de la salle ? (ben oui, on est à une conférence quand même ! Moi ? Mais non j’suis pas mégalo !)
- Tu fais de l’humour ou t’es vraiment attardé ? Je vais t’expliquer comment fonctionne généralement un packer, j’espère que tu as quelques notions en assembleur sinon tu ne pourras pas suivre. Ecoute moi :
Un packer est un programme créé par une société, ce petit programme a pour but de compresser et/ou protéger le programme contre les méchants crackers. Il est donc dans l’intérêt de tous que le packer s’installe dans le programme d’une manière invisible pour celui-ci. Le packer ne doit pas interférer avec le programme, il est donc obliger de sauvegarder la valeur de tous les registres avant son exécution, et de les restaurer une fois qu’il a fini son action de compresser/cryptage. La fonction permettant de sauvegarder tous les registres est pushad, la fonction permettant de les récupérer est popad. Une fois que le LOADER a fini de travailler, il restaure les registres et passe la main au programme en sautant vers l’OEP de celui-ci.
Avec UPX, cette étape ce fait directement après le popad. On aura donc un code du style
Popad
Jmp OEP
Ici oep est une adresse, l’adresse où le programme véritable commence. Il suffit donc de chercher dans le code quelque chose de ce style là. Et comme pour nous simplifier le vie, ce code est placé tout en bas du listing ! (Merci à ReverseMe de me l’avoir indiqué !).
Donc on lance Olly, on ouvre l’unpackme.exe et on va tout en bas (presque tout en bas :P le code se situe avant les octets libres). Et on voit :
On va donc poser un breakpoint sur ce jump avec F2, pour que le programme s’arrête au moment de sauter vers l’OEP. A ce moment du programme on est sûr que le programme est complètement décompressé.
On lance le programme et LordPe. On regarde dans la fenêtre des processus en cours et on cherche notre unpackme.exe qui se situe presque tout en bas. Une fois qu’on l’a trouvé on fait un clic droit dessus puis on choisi dump full. LordPe nous demande où on veut enregistrer notre dump donc là vous vous démmerdez.
Voilà, on se retrouve donc avec un dump qui n’est pas encore fonctionnel. Notez l’adresse de l’OEP, qui est 401188, on en aura besoin pour les modifications du PE.
On passe directement à l’étape 3 étant donné qu’on a récupéré notre OEP avant de faire le dump.
3)
Correction du PE
Alors là on entre vraiment dans les choses sérieuses……nan c’est pas vrai, c’est facile aussi :P
Donc là vous réouvrez LordPe et vous cliquez sur « PE Editor » et vous allez chercher notre dump. Ne soyez pas appeurés, il n’y a qu’une valeur à modifier ! Celle de l’Entry-point en au
à gauche. Pour trouver l’entry-point on fait la valeur de l’OEP moins celle de l’ImageBase.
Donc ici l’entry-point vaut 1188.
Vous cliquez sur save puis sur OK.
4)
Reconstruction de l’IAT
Donc là on quitte Olly et on va lancer IMPrec, qui est aussi facile à utiliser que……que…..qu’une fourchette !
Avant de lancer Imprec vous devez lancer votre programme packé.
Une fois que tout est lancé vous vous retrouvez avec la fenêtre d’IMPrec.
Voici le déroulement des étapes :
1) Sous « Attach to an active process » vous sélectionnez notre unpackme.exe
2) Modifiez l’OEP sous « IAT Infos needed »
3) Cliquez sur IAT Autosearch et le programme vous indique qu’il a trouvé quelque chose.
4) Cliquez sur « Get Imports » et IMPrec vous donne les fonctions importées.
5)On clique sur Fix dump et une fenêtre s’ouvre. On va chercher notre dump de tout à l’heure et on clique sur OK. IMPrec vient de reconstruire l’IAT de notre dump.
Petite capture d’écran pour vous aider :
Vous voyez, c’était pas si difficile. !
Vous pouvez maintenant lancé votre dump et théoriquement tout devrait marcher. Si vous avez une erreur c0000005 c’est qu’il y a un problème au niveau de l’IAT, donc recommencez l’étape 3 en faisant bien tout ce que j’ai dis et ça devrait rentrer dans l’ordre.
Bon, on va terminer l’exercice ! Donc vous lancez votre identifier préféré et vous ouvrez le dump avec. On voit que le prog a été codé en Visual basic. Donc on rentre ça dans l’unpackme et c’est fini !!!
Tutorial réalisé par Kef le dimanche 18 avril 2004