En gros c'est une méthode qui va permettre de restaurer un programme tel qu'il l'était avant qu'il ne soit packé par un packer tel que aspack, upx, armadillo, safedisc etc... L'exécutable obtenu sera non seulement utilisable mais il sera aussi possible de le désassembler en obtenant le code, les fonctions importées, les datas, les ressources bref tout ce qui était compressé en vue d'opérations tel que du cracking ou du reverse et c'est bien ça le but final de l'unpacking.
Bien entendu il existe pour certains packers des tools qui vous feront ça automatiquement. Mais savoir unpacker manuellement est très instructif, sans compter qu'il existe des packers qui n'ont pas de tools permettant de les unpacker automatiquement. De plus si vous êtes un peu programmeurs à vos loisirs vous pourrez mettre au point votre propre unpacker générique pour le packer de votre choix en automatisant les méthodes manuelles.
L'unpacking n'est pas très compliqué en soit mais demande un peu de temps et de travail. Cependant il nécessite tout de même une bonne connaissance sur la structure d'un fichier PE.
J'ai donc eu envie de créer une suite de tutorial en examinant le cas de chaque packer et de donner un exemple concret de son unpacking en manuel. Les packers fonctionnant toujours à peu près pareil, il sera simple de faire référence au tutorial correspondant au packer pour unpacker de la même façon que j'ai procédé votre programme packé.
Je vous recommande avant tout de bien vous documenter sur le PE pour une compréhension plus aisée. Pour cela voici quelques documents indispensables :
Il y a 2 façons de voir l'unpacking.
Voir aussi un mix des 2 méthodes en ne reconstruisant qu'une partie du programme.
Voici d'une vue générale la liste des actions qu'il faudra effectuer pour unpacker un programme :
Pour cela on se sert d'outils tels que Procdump, LordPe, IceDump etc...
Un dump est en gros une image du programme qui tourne en mémoire car à ce moment la il sera décompressé ou décrypté dans la plupart des cas. Par contre il faudra rectifier quelques infos dans le PE avant de le rendre exécutable car si vous essayer de lancer le dump il va crasher lamentablement.
L'entry-point actuel du programme a été redirigé par le packer vers une routine, que l'on appelle loader, qui a été ajouté au programme et qui permet à son lancement de le dépacker en mémoire. A la fin de cette routine, celle ci effectue un saut vers l'entry-point original pour exécuter le déroulement normal du programme.
Un dump étant déjà dépacké, cette routine ne sert plus a rien et nous pouvons donc la bi-passer en sautant directement sur le déroulement normal du programme c'est à dire sur l'entry-point original (OEP).
Sachant qu'à la fin de la routine de dépacking celle-ci va sauter vers l'OEP. Le seul moyen de retrouver l'OEP est de tracer avec un debugger cette routine jusqu'a ce moment précis. Chaque packer à sa petite méthode pour sauter vers l'OEP il n'y a donc pas de règles précises pour le retrouver.
Je vous donne la méthode que j'utilise et qui pour moi est la plus simple et la plus rapide :
J'utilise le debugger Windbg qui fourni un log du code tracé, Il suffit de poser un bp sur l'entry-point actuel et de rester appuyer sur le bouton trace (F10) jusqu'au moment ou le programme se lance, à ce moment la, on fait un break dans le debugger et on examine le log en remontant pour trouver le moment où nous changeons de segment et où ce saut vers l'OEP a été effectué. On peut aussi commencer le trace à partir d'un BPX sur l'api LoadLibrary, qui est souvent appelé par le loader d'un packer, plutôt que du tout début.
Bon d'accord c'est une méthode bourrin, mais au moins c'est rapide et efficace. Apres quand on connaît bien le packer auquel on à faire, on peut élaborer des stratégies plus spécifiques comme retrouver un bout de code qui reviendrais toujours (signature) pour poser un break-point et trouver l'OEP.
C'est sûrement ici le point le plus délicat. Pour certain packer vous n'aurez rien à toucher si ce n'est corriger l'adresse de l'Import Table dans le PE. Par contre pour d'autre et en grande majorité il faudra corriger certains éléments de cette table, voir en réécrire une complète ou partielle. Mais rassurez vous c'est relativement simple et amusant une fois que l'on à compris son fonctionnement :).
J'ai jugé préférable d'écrire un tutorial complet et sur ce vaste et délicat sujet, ce qui occupera le chapitre 2 de cette série de tutoriaux.
Une fois que tout est prêt il nous faut faire les finitions et ajuster le PE-header face aux modifications que l'on y a apporté, comme :
Le reste dépend directement des changements apportés et du packer mais en règles générales on retrouve ces 3 points.