Titre

---------------------------------------- Chapitre IX - Les packers ----------------------------------------

UPX

 

Cible :

Testupx

Outils nécessaires :

OllyDbg (by Oleh Yuschuk)
Imprec
Lord-Pe
Peid 0.95

(Tous les programmes et outils de ce tutoriel sont stockés dans le répertoire Pack).

 

1 - Introduction

C'est un outil qui permet à la fois de compresser (un peu comme le ferait winzip ou winrar) un fichier exécutable ou une dll et qui souvent le sécurise en rajoutant différentes protections. Le fichier obtenu conserve son type (.exe ou .dll) et reste ainsi utilisable comme à l'origine.

Pour simplifier on ne parlera que d'exécutable (.exe) sachant que le principe est le même dans le cas d'une bibliothèque (.dll).

Le packer va créer un nouvel exécutable dans lequel il va intégrer une version compressée de l'exe d'origine ainsi qu'un loader. Le loader (chargeur en français) est une routine qui va permettre de décompresser l'exécutable d'origine en mémoire lorsque l'on lancera le programme packé. Ainsi, le programme d'origine sera uniquement lisible en mémoire. Si on ouvre la version packée présente sur notre disque avec un debugger, seule la routine du loader sera compréhensible, le reste étant compressé, nous ne pourrons pas l'analyser. Il nous faut donc recopier l'exécutable d'origine à partir de la mémoire. Puis le rendre fonctionnel. On parle dans ce cas d'unpacking. Mais ce n'est pas aussi simple qu'il n'y parait ...

Pour aborder ce chapitre, il faut tout d'abord quelques bases sur la structure d'un fichier exécutable.

Tous les programmes destinés à tourner sous Windows doivent respecter une norme : il s'agit du format PE ( Portable Executable) qui établit des règles strictes sur l'organisation des différentes parties d'un programme. Nous n'allons pas rentrer dans le détail mais juste voir de façon simplifiée quelques points pour vous permettre de comprendre la suite du tuto.

C'est l'en-tête du programme, pour ainsi dire le sommaire. C'est lui qui va donner les indications permettant à Windows de charger correctement l'exécutable. On va par exemple trouver dans le PE HEADER l'adresse de la première instruction à exécuter (l'EP, Entry Point, point d'entrée), l'adresse des différentes sections, quel compilateur a été utilisé, etc ...

Ce sont en quelques sortes les paragraphes du programme. Par exemple :

.text : le code
.data : les variables initialisées
.rdata : les données en lecture seule
.rsrc : les ressources (images, sons ...)

L'adresse de chaque section se retrouve dans le PE Header.

C'est l'adresse de la première instruction (code) que doit exécuter Windows dès que le programme a été chargé. Lorsqu'un exécutable a été packé, c'est l'adresse de début du loader. Le point d'entrée de l'exécutable décompressé en mémoire devient l'OEP ( Original Entry Point).

Vous avez pu voir lors des précédents cours qu'un exécutable, lors de son exécution, fait appel aux fonctions des dlls (les APIs) de Windows (GetWindowText, GetDlgItemText ...). Mais comment fait-il pour savoir où se trouvent ces fonctions ? En fait il n'en sait rien. Lors de la compilation du projet, toutes les fonctions nécessaires au programme sont listées dans un tableau appelé IAT :

004xxxxx      GetWindowText
004xxxxy      GetDlgItemText
004xxxxz      ...

Lors du chargement du programme, Windows va lire ce tableau et remplacer les noms des fonctions par leurs adresses. L'exécutable fait ses calls vers les adresses de son IAT et le call est alors redirigé vers l'adresse créée par Windows.

C'est l'adresse à laquelle est chargé le programme, en règle générale 400 000h.

Cette introduction a pour seul but de vous apporter un minimum de compréhension sur les termes employés lorsque l'on aborde l'unpacking. Si vous voulez approfondir ce sujet, je vous invite à faire vos propres recherches sur le net, la documentation est nombreuse et le sujet est vaste !

 

2 - Observations

Il faut savoir qu'UPX n'est pas à proprement parler un packer mais un simple compresseur d'exécutable qui n'apporte aucune protection.
Certes il empêche de voir les strings datas, de lire le code du programme original, modifie le PE header et renomme/crée ses propres sections nommées UPX0 et UPX1 mais il n'ajoute aucune sécurité supplémentaire.

Regardons un screenshot de la cible dans Peid :

Peid

 

3 - Fonctionnement basique d'un packer:

Un packer/compresseur va décompresser le programme en mémoire et seulement une fois sa routine de décompression terminée, donner la main à l'exécutable virtuel ainsi créé.

Dans ce cas-ci, Upx, comme les autres packers/compresseurs, aura son Entry-Point à un offset différent de celui du programme original.

Le but est donc de retrouver l'Entry-point du programme original avant qu'il n'ait été compressé par Upx.

Upx a une signature très simple dans son fonctionnement : il commence toujours par un PUSHAD et se termine toujours par un POPAD et ce y compris la dernière version du jour, la 3.09 !

Il va pousser sur la pile le contenu de tous les registres afin d'exécuter la décompression du programme original en mémoire et remettre les registres comme ils étaient avec son POPAD une fois terminé pour ensuite utiliser un JMP vers l'Original Entry-Point de la cible décompressée en mémoire !

 

4 - Lançons la cible dans Ollydbg :

Si comme moi vous tombez sur l'écran juste ci dessous, vous remarquerez que vous n'êtes pas dans la cible mais dans une dll (1). Pour aller dans la cible à analyser, cliquer sur le bouton Alt+E (2) :

Olly

puis double-cliquez sur la ligne de votre cible comme indiquée par la flèche sur l'image ci-dessous :

Olly

Vous vous retrouvez enfin au bon endroit c'est à dire à l'Entry-Point d'UPX et sa fameuse première instruction PUSHAD :

Olly

Sachant qu'UPX commence par un PUSHAD et se termine par un POPAD, cherchons ce fameux POPAD en scrollant vers le bas comme dans l'image ci-dessous :

Olly

Nous nous retrouvons ici :

Vous voyez la ligne avec le POPAD (flèche 1) et 6 lignes plus bas un JMP vers un offset... (Flèche 2).

Sélectionnons la ligne du JMP puis appuyons sur F2 afin de mettre un breakpoint juste à la fin de la décompression d'UPX :

Olly

Une fois ceci fait, vous avez l'offset surligné en rouge pour vous indiquer qu'il y a un breakpoint sur cette ligne !

Olly

Lançons Olly en pressant F9 afin qu'il breake sur la ligne que nous lui avons demandé :

Olly

Appuyons sur F8 afin d'exécuter le JMP et nous atterrissons à l'Entry-Point Original ou OEP !

Olly

Maintenant c'est bien, on est à l'OEP de la cible, mais on a toujours pas de fichier fonctionnel, tout ce qui est ici se trouve uniquement en mémoire :-(

Nous allons pour ce faire, dumper le fichier décompressé (créer une copie/sauvegarde sur le disque) et reconstruire les imports (IAT) car ceux-ci correspondent aux offsets d'UPX !

Avec la version 2 d'Ollydbg, il n'y a pas encore de plugin pour dumper directement comme dans la version 1, mais nous allons utiliser Lord-Pe.

Une fois LordPe ouvert, sélectionner notre fichier cible, puis clic droit ensuite cliquez sur dump full !

Lord-Pe

Si tout s'est bien passé, vous avez un fichier nommé dumped.exe sur votre disque dur, ce fichier n'est pas encore valide car les imports sont encore dirigés vers les offsets UPX. Pour terminer le travail correctement et avoir un fichier valide, il faut rediriger les imports avec Imprec, programme qui fait quasi tout le boulot à notre place !

Ouvrez donc Imprec et sélectionnez notre fichier cible :

Imprec

Une fois fait, nous arrivons ici et nous voyons que notre imagebase n'est pas bonne car elle contient les informations d'UPX, or nous voulons utiliser les imports de la cible originale !

Si vous regardez dans Olly, l'OEP où se trouve votre PUSHAD est 4600F0h c'est l'OEP du programme compressé 400000h+600F0h

Nous on veut remettre l'OEP du programme original à savoir 401000h donc 400000h+1000h, nous devons donc remplacer 600F0h par 1000h :

Imprec

Une fois le bon OEP entré, nous cliquons sur Iatautosearch pour voir s'il trouve quelque chose ...

Bingo il a trouvé, on peut donc cliquer sur ok afin de valider !

Imprec

Après avoir cliqué sur IATautoSearch (1)

Maintenant il faut cliquer sur getimports (2) pour voir s'il va nous trouver les imports en rapport avec notre OEP.

Il en a trouvé 3 et il n'y a pas d'erreur, ils sont tous les 3 valides (3).

Si vous avez des doutes, vous pouvez vérifier en cliquant sur showinvalid, mais il restera comme cela vu que tous les imports sont tous bons.

Nous pouvons donc fixer notre dump (4) en cliquant sur le bouton fix dump et en indiquant l'emplacement de notre fameux fichier dumpé avec LOrdPe !

Si tout s'est bien passé, vous devriez avoir la même ligne bleue que moi, saved succesfully !

Imprec

Vous devriez avoir un fichier dumped_.exe valide, c'est à dire qu'il est fonctionnel comme le fichier cible de départ , avec le compresseur Upx en moins !

Ce qui veut dire que votre fichier est prêt à être craqué !

Un scan du fichier cible avec Peid avant de commencer, on voit bien qu'il est compressé avec Upx :

Peid

Un petit scan avec Peid après notre unpacking pour voir si UPX est bien retiré :

Peid

On peut constater que Peid nous indique un autre packer, il s'agit d'une fausse signature réalisée par Goldocrack lors de la création de son crackme, mais on voit en tout cas qu'Upx n'est plus !

J'espère que vous avez appris quelque chose, UPX étant une protection plus que simple !

 

 

Precedent        Sommaire        Suivant