Cracking débutants FireBurner

FireBurner 1.06 - Dump Manuel d'UPX

Par Oasis

1. Introduction

Bonjour les gens. Je m'intéresse depuis peu aux programmes packés et je vais tenter de vous faire partager cette passion. Il y aura probablement toute une série de tuts sur ce type de protections. On va commencer facile en abordant UPX qui est sûrement le packer le plus simple à contourner.
Comment sait-on qu'un exe est packé ? Voici les symptômes : aucune string quand on désassemble, mention du packer au début du listing désassemblé et/ou vers la fin plein de BYTE 10 DUP(0), sections portant le nom du packer quand on analyse les sections avec le PE Editor de Procdump. Pour ma part, j'analyse toujours un prog avec Stud_PE, avant même de le désassembler car y a rien de plus chiant que d'attendre 5 minutes de désassemblage pour se rendre compte qu'il est packé. Chaque packer à sa propre "signature", c'est à dire une série d'octets spécifiques qui sera toujours la même pour tous les progs passés par ce packer. La signature d'UPX est 61 E9. C'est notamment grâce à elle que Stud_PE va conclure que FireBurner est packé par UPX. Comme j'écris ce tut pour ceux qui ne sont pas très à l'aise avec les compressions, il y a beaucoup d'explications afin que le sujet soit d'une limpidité sans faille. Toutefois, si vous bloquez à un moment ou un autre, n'hésitez pas à crier à l'aide... Pour contourner UPX, il suffirait de faire un dump automatique avec Procdump et ce serait fini en dix secondes, seulement vous n'auriez rien appris. Donc ici on va réaliser un dump manuel, ce qui sera une base indispensable pour d'autres packers qui mettent procdump le nez dans la choucroute...
Un petit mot à propos de notre cible : FireBurner est un prog génial que je vous conseille d'acheter. Je rappelle que ce tut est destiné à comprendre comment contourner un prog packé par UPX et non pas à faire perdre de l'argent au créateur du logiciel...

2. Let's go

On désassemble avec Windasm et on voit que le bouton des strings est désactivé. On voit aussi au début ceci:

+++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++
//********************** Start of Code in Object UPX0 **************
Program Entry Point = 005C3BF0 (FireBurner.exe File Offset:00050FF0)

Une notion importante est celle de l'entry point : l'entry point est la première instruction que le prog exécute. Si le prog n'est pas packé, rien à ajouter. Par contre, quand un packer est passé par là, cette entry point n'est pas la première instruction du programme en lui-même mais bien la première instruction qui va être exécutée, donc la première instruction du loader. Voir définition du loader au point 3. Donc dans le cas des exe packés, il faudra bien faire la différence entre Entry Point ( = Entry Point du Loader) et Original Entry Point (OEP) qui elle est la véritable première instruction du programme.

On cherche la signature d'UPX. Il y plusieurs fois 61 E9, il faut toujours prendre la dernière, celle suivie de kilos de 00. C'est même pas la peine d'utiliser Search/Find Text : on descend à la dernière instruction et quelques lignes au-dessus, on voit ceci :

:005C3D52 61 popad
:005C3D53 E97C31EEFF jmp 004A6ED4

popad = restauration des registres. Ce popad va de pair avec un pushad (opcode 60) placé ici bien avant dans le listing. Pushad signifie que tous les contenus des registres sont placés sur la pile, avant le début de la décompression (quelques fois d'ailleurs, ce pushad sera remplacé par une suite de pop eax, pop ebx,...). Tout de suite après, la décompression se réalise. Puis intervient la restauration des registres, c'est à dire que le prog reprend de la pile le contenu des registres transférés dans celle-ci par pushad et les replace dans les registres. Puis saut vers l'OEP, la véritable première instruction du prog, dont l'adresse est ici 4A6ED4.

3. Le principe du dump.

Un programme packé se compose de deux parties : le programme compressé qui est illisible tel quel quand on le désassemble et le loader, qui lui est en clair et dont la fonction est de décompresser en mémoire le programme packé. Ainsi quand on lance le prog, le loader décompresse celui-ci en mémoire et quand cette décompression est terminée, il rend la main au prog qui est à présent "en clair" (ici : jmp 004A6ED4). Pour réaliser notre dump, on va modifier cette dernière instruction par jmp eip, ce qui aura pour effet que le programme complètement unpacké en mémoire va boucler sur lui-même indéfiniment, ce qui va nous laisser le temps de copier le contenu de la mémoire sur notre disque, on sauvegarde ainsi le contenu de la mémoire (le prog décompressé) sur notre système.

4. Le dump automatique avec Procdump

Uniquement pour info puisque nous, on le réalise manuellement.

































5. Manual dumping.

Pour notre manual dumping, on fait une copie du prog original et on ouvre un éditeur hexa : on remplace 61E9 de l'adresse 5C3D52 (offset 51152) par EBFE pour pouvoir le faire boucler en mémoire. On sauve et quitte l'éditeur. On lance le prog modifié, il semble ne rien se passer sauf qu'il boucle sur lui-même à l'arrière-plan. On lance procdump/Pe Editor, on pointe le curseur sur n'importe laquelle des applications dans tasks, clic droit/Refresh list. On sélectionne notre prog dans ceux qui tournent. Clic droit, dump full. Si cela se passe bien, Procdump vous demande à quel endroit et sous quel nom sauver le dump.
On kill le process pour qu'il ne boucle pas indéfiniment en mémoire, par Contr alt Del/Fin de tâche. Si vous n'êtes pas assez rapide, la mémoire est saturée et le PC est planté. Mais pas peur...

Un oeil dans l'explorateur pour se rendre compte que le prog unpacké fait 1,77 M alors qu'on vient de 333 k (UPX est vachement plus performant que Win Zip quand il s'agit de zipper un exe...). Le dump a réussi. On lance le prog dumpé. Et bardaf un joli message d'erreur. Où a-t-on fait une bourde ?

Réfléchissons... Au début on a vu la différence entre Entry Point et Original Entry Point (OEP). Puisque notre prog est maintenant dumpé, la première instruction devant être exécutée est l'entry point du prog et non l'entry point du loader dont on a plus besoin. Il faut donc remplacer l'entry point par l'original entry point. Souvenez-vous, au début quand on a désassemblé, Windasm affichait ceci :

Program Entry Point = 005C3BF0 (FireBurner.exe File Offset:00050FF0)

Donc Procdump/PE editor. On lit dans le champs entry point: 1C3BF0. Ajoutons-y les 400000 du champ Image Base et on obtient ce que Windasm affichait : 5C3BF0 (Première instruction du loader).
Et souvenez-vous, quand on cherchait la signature, on avait ceci :

:005C3D52 61 popad
:005C3D53 E97C31EEFF jmp 004A6ED4

Ce saut "rend la main" au prog quand il est unpacké. C'est donc, je me répète, l'OEP de notre programme. Concrètement, on fait: 4A6ED4 - 400000 (Image Base)= 0A6ED4 que l'on reporte dans le champs entry point de Procdump, à la place de l'autre. On dit ainsi au prog de pointer sur sa première instruction et non plus sur le loader. Pour trouver l'OEP d'un prog packé, on peut aussi utiliser PEid.

Windasm, on désassemble : et hop voilà les strings.... C'est magique... Le point suivant explique le dump que l'on vient de réaliser mais avec SoftIce. Pour le crack proprement dit de FireBurner, rendez-vous au point 6. Maintenant que nous n'avons plus UPX dans les pattes, reste plus que la cerise sur le gâteau...


5b. Réaliser un dump avec SI.

Ce qui est chiant avec SoftIce, c'est de se rendre à l'endroit du prog que l'on veut. Pour éviter cela, un bon truc est de remplacer avec HView le 61 de la signature par CC. Dans Sice, on pose un BPint 3 (Breakpoint on interruption), ainsi il va breaker sur notre CC qui remplace le popad. On lance le prog, il breake. Tout de suite il faut remplacer le CC par 61 sinon le prog va se planter :

a pour mode assembleur, enter
tapez popad, enter
F10 pour se déplacer sur le jmp oep
a pour mode asm, enter
tapez jmp eip, enter (ainsi le prog boucle sur lui-même en mémoire)
Contr D pour sortir de Si.
Sauvez le dump avec procdump et kill le prog qui tourne.

6. Time limit.

Avant tout, comme ce prog est assez lourd à désassembler, une fois que c'est le cas, cliquez sur Disassembler / Save Disassembly Text File. Et pour y revenir, Project / Open Project File. On avance son horloge d'un mois et on lance le prog... Dialogbox qui ne permet que d'entrer le serial et donc pas accès au programme. On cherche la string " Your 15 days evaluation...". Quelques lignes plus haut on voit :

:004A47A3 803800 cmp byte ptr [eax], 00
:004A47A6 7452 je 004A47FA

Si on se rend à l'adresse où il saute(4A47FA), on est en plein dans le prog, donc on peut supposer que si la période d'essai est terminée, eax vaudra 1 d'où la comparaison ne sera pas égale et il ne sautera pas dans le prog et arrivera forcément sur notre string. Donc on force le saut en le transformant en jmp inconditionnel (EB remplace 74 à l'offset A3DA6). On teste, ça roule.

7. Registered / Unregistered switch

Quand on est face à la fenêtre principale du prog, on lit (Unregistered) dans la barre de titre. Or en regardant les strings au début, deux strings qui se suivent de près m'avaient sauté aux yeux :
FireBurner V1.06 (Registered)
FireBurner V1.06 (Unregistered)

Dans le code cela donne ceci :

:004A4AF6 803800 cmp byte ptr [eax], 00
:004A4AF9 740E je 004A4B09

* Possible StringData Ref from Data Obj ->"FireBurner V1.06 (Registered)"

:004A4AFB BA504E4A00 mov edx, 004A4E50
:004A4B00 8BC7 mov eax, edi
:004A4B02 E8B5EDF8FF call 004338BC
:004A4B07 EB0C jmp 004A4B15

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004A4AF9(C)

* Possible StringData Ref from Data Obj ->"FireBurner V1.06 (Unregistered)"

:004A4B09 BA784E4A00 mov edx, 004A4E78

Pas besoin d'avoir fait maths fortes. C'en est même à mourir de rire. Le premier saut nous emmène dans la version Unregistered, suite à la comparaison avec la valeur en eax qui doit être 0 si on est pas enregistré. A l'inverse si nous étions enregistré, eax serait égal à 1, donc le saut ne se ferait pas et nous arriverions dans la version Registered. Capito ? Donc on noppe le saut (remplacer 740E par 9090 à l'offset A40F9). Relançons le prog : on lit maintenant dans la barre de titre Registered. Je n'avais pas, avant ce prog, prêté attention à ce type de switch, mais c'est à retenir car je me rends compte qu'il est fort répandu.


8. Nag "Please Register"

Quand on clique sur about un nag nous apprend "Please Register", on repère cette string. On arrive sur celle-ci par un saut qui se décide en 4A4191. On s'y rend et on voit :

:004A418E 803800 cmp byte ptr [eax], 00
:004A4191 7458 je 004A41EB

* Possible StringData Ref from Data Obj ->"This Copy Registered to"

Si la comparaison est égale à 00, il va sur "Please Register..." et à l'inverse, si eax vaut 01, il ne saute pas et on est dans la partie "This Copy Registered to". Donc à l'offset A3791, on noppe le je par 9090.

On lance le prog et dans about on voit notre nom en grand. Et pis c'est tout. Qu'est-ce qu'on se marre... A plus.

Oasis, 25.11.03