Inside Out - Blog CyberSécurité Blog

Comment dépacker un malware avec x64dbg

Comment dépacker un malware avec x64dbg | Varonis

Dans un précédent billet, je vous ai expliqué ce qu’était x64dbg et vous ai présenté certaines de ses fonctionnalités, ainsi que leur intérêt dans le cadre de l’analyse d’un malware. Cet article prend la forme d’un didacticiel pour x64dbg, dans lequel je dévoile ma méthodologie pour procéder à l’ingénierie inverse d’un malware et explique comment utiliser cet outil pour dépacker un malware.

Scénarios d’utilisation de x64dbg :

image des scénarios d’utilisation de x64dbg

Dans cet article, nous allons aborder les points suivants :

  • Dépacker manuellement un malware
  • Recharger un malware décapsulé dans x64dbg
  • Analyser le malware et son fonctionnement

Avant d’utiliser un outil comme x64dbg pour procéder à l’ingénierie inverse d’un malware, je prends soin de procéder à l’analyse comportementale du fichier binaire à l’aide d’outils gratuits. Cette première étape me permet de comprendre ce que fait le malware lorsqu’il compromet un appareil. A l’aide de ce comportement, je peux déduire certains indicateurs de compromission clés, comme du trafic réseau, des fichiers écrits sur le disque ou des mécanismes de persistance.

Je me fais également une vague idée des objectifs du créateur du malware. Sa motivation peut être financière (ransomware), mais il peut aussi essayer de mettre en place une porte dérobée sur un réseau (cheval de Troie d’accès distant).

Sans cette étude préalable, je ne me risquerais pas à ouvrir le malware dans x64dbg, car je serais forcé d’analyser le code assembleur à l’aveugle. De plus, je pourrais être confronté à du code packé m’empêchant de procéder à une analyse pertinente.

En effet, les malwares sont souvent packés, de sorte à ce que leur code malveillant soit masqué. La création d’un tel code demande du temps : les malandrins mettent donc tout en œuvre pour qu’il ne soit pas facile de l’étudier et de déterminer rapidement ce qu’il fait et comment le neutraliser.

Un malware packé est « encapsulé » dans du code, ce qui permet de masquer les lignes écrites par l’auteur du malware. Cette technique est appelée « packing ». La bonne nouvelle, c’est que x64dbg permet bien souvent de dépacker manuellement un malware. Il est alors possible de charger une nouvelle fois le fichier dépacké dans ce même outil pour commencer l’analyse à proprement parler.

Il est très utile de savoir dépacker un malware. Cependant, une fois cette opération effectuée, par quoi commencer l’analyse ? Tout d’abord, vous ne devez pas analyser chaque ligne de code une par une, vous y passeriez une éternité. L’analyse dynamique que vous avez réalisée en amont peut vous orienter vers un comportement d’intérêt. Par exemple, le malware génère peut-être des noms de fichier aléatoires sur chaque appareil qu’il infecte et vous pourriez donc vous pencher sur la manière dont sont générés ces noms.

Ma méthodologie :

Tout d’abord, n’oubliez jamais qu’un malware se compose de plusieurs fonctions que son auteur a lui-même créées ou qu’il a importées.

Par exemple, un malware peut disposer d’une fonction de création d’un fichier sur le disque. L’analyse de cette fonction dans x64dbg permettrait alors de déterminer où ce fichier est écrit et quel nom lui est donné. L’auteur du malware pourrait parfaitement écrire une telle fonction, mais Windows en intègre déjà plusieurs faisant la même chose : il a donc également la possibilité de les importer. Ainsi, dans certains cas, plutôt que d’écrire une fonction, les créateurs de malwares importent des fonctions légitimes de Windows qui effectuent une partie du travail à leur place.

Ces fonctions sont appelées API Windows. Windows intègre diverses bibliothèques incluant des fonctions uniques. Ces bibliothèques sont appelées fichiers DLL (Dynamic Linked Libraries).

Par exemple, le fichier Kernel32.dll contient l’API « WriteFile ». Le malware peut donc l’importer et l’utiliser pour écrire des fichiers sur le disque. Lorsqu’un malware importe des fichiers DLL, un analyste peut utiliser cette information pour en déduire les capacités globales du malware. Les API Windows importées forment la table IAT (Import Address Table).

Vous devez commencer votre analyse d’un malware dans x64dbg par la fonction principale. Il s’agit de la partie centrale du code écrit par l’auteur du malware.

Toutefois, au sein de cette fonction, le malware appelle nécessairement d’autres fonctions, qui peuvent avoir elles aussi été écrites par l’auteur du malware ou être des API Windows importées. Par exemple, si le malware a besoin de créer un fichier, il peut utiliser l’API Windows CreateFileA pour le faire. Comme il s’agit d’une fonction de Windows légitime, nous n’avons aucun intérêt à analyser son code assembleur. En revanche, il serait intéressant de déterminer la valeur retournée par cette fonction, ainsi que les arguments qui lui sont transmis avant son appel ou son exécution.

Ce type d’analyse peut nous permettre de savoir comment se nommera le fichier et où il sera installé sur le disque. De plus, l’étude de la valeur renvoyée par la fonction peut également révéler si l’opération a réussi.

L’image ci-dessous illustre l’imbrication des appels de fonctions.

illustration d’une fonction

Dans le cadre de notre ingénierie inverse, il serait intéressant d’analyser une fonction écrite par l’auteur du malware. Reprenons l’exemple de l’image ci-dessus et imaginons que la fonction « AAA » a été écrite par l’auteur du malware et que je souhaite, de fait, l’étudier de plus près.

x64dbg propose deux mécanismes que vous utiliserez régulièrement : Step over et Step into. Si mon pointeur d’instruction (EIP), c’est-à-dire le pointeur vers la prochaine instruction assembleur qui sera exécutée, est défini sur « CALL AAA », je peux choisir de passer cette instruction (Step over) ou d’y accéder (Step into). Si je choisis de la passer, la fonction est exécutée, mais les instructions correspondantes ne sont pas affichées. Si je choisis d’y accéder, je suis redirigé vers l’espace d’adresse où cette fonction commence, et je peux en voir le contenu.

Cette fonction peut inclure d’autres fonctions d’intérêt. Dans notre exemple, je pourrais accéder à la fonction CCC afin de visualiser l’espace d’adresse où commence cette fonction. En parcourant le code, je finirai par arriver à la fin de la fonction, marquée par la commande de retour. Une fois cette commande exécutée, je passerai à l’instruction qui suit directement l’appel à la fonction « CCC » et me retrouverai donc dans la fonction « AAA ».

Je peux de nouveau parcourir le code jusqu’à arriver à une instruction de retour et passer à l’instruction qui suit directement l’appel à la fonction « AAA ».

Les appels aux API Windows peuvent être identifiés par leur nom, qui commence par la dénomination du fichier DLL à partir duquel les API sont chargées ou bien par le nom documenté par Microsoft. Dans cet exemple, j’ai utilisé le nom « BBB ». Toutefois, il s’agit bel et bien d’une API Windows, et je n’essaierai donc pas d’accéder à cette instruction, car elle n’a pas été écrite par l’auteur du malware. En revanche, les informations envoyées sur la pile avant l’appel de la fonction et la valeur renvoyée par celle-ci après son exécution peuvent être intéressantes.

Cette brève présentation devrait vous aider à comprendre la méthodologie utilisée pour analyser un malware dans un débogueur. Cette activité peut s’avérer extrêmement chronophage, il est donc déconseillé d’analyser chaque fonction écrite par l’auteur du malware. Comme je l’ai mentionné précédemment, appuyez-vous sur votre analyse comportementale pour déterminer les points d’intérêt qu’il convient de mieux comprendre.

L’échantillon que nous analysons est le malware Emotet. Lorsqu’il infecte une machine, il génère un nom aléatoire pour son fichier. Lors de mon analyse, je me suis donc concentré sur les appels aux API qui généraient cette activité, puis j’ai observé ce que faisait le malware à ce moment-là.

Analyse étape par étape d’un malware à l’aide de x64dbg :

Je vais vous présenter une technique que j’utilise pour identifier un malware packé, puis dépacker ce malware manuellement avec x64dbg.

Identification d’un malware packé :

Attention : n’essayez pas d’analyser un malware sans avoir mis en place un environnement virtualisé sécurisé. x64dbg ne doit pas être installé sur votre machine hôte pour analyser des malwares. De plus, la machine hôte doit disposer d’un système approprié de protection contre les malwares.

Échantillon : b1cad1540ecb290088252635f8e130022eed7486eb128c0ca3d676945d60a9fc

Il existe plusieurs techniques pour déterminer si un malware est packé. Pour ma part, j’exécute le malware dans une machine virtuelle sur laquelle s’exécute l’outil Process Monitor (ProcMon). ProcMon enregistre l’activité du système de fichiers de la machine dans laquelle il s’exécute et permet de filtrer les résultats pour mettre en évidence tous les processus nouvellement créés. Le malware que j’ai déclenché dans cette démo s’appelle « 267.exe ». La capture ci-dessous présente quelques-uns des processus qui ont été repérés dans la machine virtuelle dans laquelle je l’ai exécuté. Les deux processus du bas sont nommés « 267.exe ». Le premier a été généré lorsque j’ai lancé le malware. La capture montre que le malware a ensuite créé un processus enfant du même nom. Cette activité correspond au dépacking du malware en mémoire, une technique nommée injection dans les processus.

procmon

Pour se dépacker, le malware crée un nouveau processus, le processus enfant illustré dans la capture ci-dessus. Ce nouveau processus enfant se voit ensuite attribuer de l’espace libre au sein du processus parent. Le code dépacké est alors injecté dans l’espace libre de ce nouveau processus enfant, d’où le nom « injection dans les processus » !

Dans cet exemple, nous constatons également que le malware se supprime ensuite du bureau pour se copier vers son emplacement permanent, C:\Windows\SysWOW64, sous le nom « loadatangent.exe ». La même technique d’injection est utilisée pour le dépacking. Le malware s’exécute désormais sur le disque sous le nom de « loadatangent.exe ».

Dépacker manuellement un malware :

Après une analyse comportementale simple, nous avons déterminé que le malware est packé et nous avons des preuves permettant d’affirmer qu’il se dépacke en mémoire. Il est désormais temps d’utiliser x64dbg pour décortiquer le malware dépacké.

En faisant glisser le malware sur l’icône de x64dbg sur le bureau, je le charge dans notre outil. La première chose à noter est l’intitulé de la fenêtre :

ntfll

Dans cet exemple, le module analysé est « ntdll.dll », un fichier DLL Windows importé par le malware. Il ne s’agit pas de code écrit par l’auteur du malware. Seul le code écrit par l’auteur du malware nous intéresse. Le module que nous devons analyser porte le nom du fichier que nous avons ouvert dans x264dbg, à savoir « 267.exe ». Dans la barre d’outils, sélectionnez Debug, puis Run pour accéder au point d’entrée du malware. Il s’agit de la fonction principale que nous avons mentionnée dans la section Méthodologie.

exécution de débogage

x64dbg exécute le code jusqu’au point d’entrée du malware. Vous pouvez vous en assurer en vérifiant si le nom du module est désormais « 267.exe » et si le commentaire « EntryPoint » apparaît dans la 5e colonne de la fenêtre principale.

point d’entrée

Avant de commencer à explorer le code du malware, nous devons encore nous fixer un objectif. Nous avons déjà vu que le malware se dépackait en créant un nouveau processus et en y injectant son code. Pour commencer, nous pouvons donc nous concentrer sur les API Windows de création de processus et d’allocation de mémoire au sein de ces processus.

Pour ce faire, nous pouvons définir des points d’arrêt sur les appels à des API Windows susceptibles d’avoir été importées par le malware à ces fins. Je vais définir un point d’arrêt sur « VirtualAlloc ». Ainsi, je peux voir à quel moment le malware alloue de l’espace mémoire à un nouveau processus, puis vérifier si cet espace d’adresse est utilisé pour injecter le malware dépacké.

Il existe plusieurs moyens de mettre en place des points d’arrêt. Pour ma part, j’utilise souvent le raccourci Ctrl+G, qui ouvre une fenêtre contextuelle. Une fois que j’ai saisi le nom de l’API Windows qui m’intéresse, x64dbg vérifie si cette valeur est présente dans le malware.

virtualalloc

Dans la capture ci-dessus, nous voyons que cette API a été détectée dans le fichier DLL Kernel32. Un clic sur OK permet d’afficher dans x64dbg l’emplacement de cette fonction.

virtualalloc 2

La capture ci-dessus montre que nous nous trouvons dans le module « kernel32.dll » et présente l’adresse de la fonction « VirtualAlloc ». Nous pourrions définir un point d’arrêt sur l’adresse de début de « VirtualAlloc », mais nous cherchons à savoir quelles données créées par cette API seront mises en mémoire (avec l’espoir qu’il s’agisse du malware dépacké).

Par conséquent, je vais plutôt placer mon point d’arrêt à la fin de la fonction « VirtualAlloc ».

Dans la capture ci-dessus, deux instructions de saut représentées par la commande « jmp ». En appuyant sur la touche Entrée lorsque ces commandes sont sélectionnées, vous suivez ces sauts, représentés par des flèches rouges.

virtualalloc

La capture ci-dessus indique que je me trouve maintenant à la fin de la fonction « VirtualAlloc », représentée par l’instruction de retour « ret 10 ».

Pour définir un point d’arrêt, faites un clic droit sur l’instruction de retour, sélectionnez Breakpoint, puis Toggle.

point d’arrêt de virtualalloc

L’adresse de l’instruction de retour est « 7685F199 ». Une fois que le point d’arrêt est défini, cette adresse devient rouge.

point d’arrêt de virtualalloc

Vous avez également la possibilité de confirmer la définition du point d’arrêt dans l’onglet Breakpoints.

onglet Breakpoints

L’image ci-dessus présente le premier point d’arrêt atteint, qui correspond au point d’entrée dans le malware. Le deuxième est celui défini pour le retour de la fonction 7685F199. Notez l’instruction assembleur et l’adresse spécifiée.

Cliquez sur l’onglet CPU pour afficher de nouveau le code assembleur. Appuyez sur Maj+8 pour revenir à l’adresse où se trouve actuellement le pointeur EIP.

point d’entrée

Nous pouvons maintenant exécuter le code et analyser les points d’arrêt atteints lorsque le malware appelle la fonction « VirtualAlloc ». Notez que ce point d’arrêt risque d’être atteint à plusieurs reprises, et vous devrez donc vous y reprendre à plusieurs fois pour mener votre analyse à bien.

Dans l’onglet Debug, sélectionnez Run pour exécuter le malware jusqu’à ce qu’un point d’arrêt soit atteint, ce qui mettra le programme en pause.

exécution de débogage

Dans la capture ci-dessous, nous voyons que le point d’arrêt a été atteint et que le pointeur EIP est désormais associé à l’adresse de l’instruction de retour sur laquelle un point d’arrêt a été placé. Notez que la partie supérieure de la fenêtre de x64dbg indique que le module actif est « kernelbase.dll », le fichier DLL dans lequel se trouve la fonction « VirtualAlloc ».

point d’arrêt de virtualalloc 3

Vous pouvez repérer la valeur de retour de la fonction « VirtualAlloc » en passant cette instruction (vous pouvez également y accéder, avec le même résultat). Pour ce faire, sélectionnez Debug dans la barre d’outils.

step into

Le pointeur EIP passe alors à l’instruction qui suit l’appel à la fonction « VirtualAlloc ». Notez que nous sommes de retour dans le module 267.exe et que l’appel à « VirtualAlloc » a été passé de manière indirecte. Cette caractéristique nous indique que plutôt que d’utiliser l’instruction « CALL VirtualAlloc », le malware a stocké la fonction « VirtualAlloc » dans le registre EDI et que l’appel a été réalisé par l’instruction « CALL EDI ». La capture ci-dessous présente l’appel au registre EDI et le stockage de la fonction « VirtualAlloc » dans ce registre.

virtualalloc

La mémoire a maintenant été allouée à l’aide de la fonction « VirtualAlloc ». Toutefois, nous devons vérifier si cette mémoire est utilisée pour y placer le malware dépacké.

En vérifiant les paramètres transmis une fois l’espace mémoire alloué, nous pouvons déterminer si le malware dépacké est stocké dans ces paramètres, mis en surbrillance ci-dessous.

paramètres de virtualalloc

Faites un clic droit sur [esp+28], puis choisissez Follow in Dump pour afficher le contenu de ce paramètre. Les options Selected Address et Address: ESP+28 aboutissent au même résultat.

vidage de virtualalloc

La fenêtre de x64dbg comportant toutes les données de vidage de l’utilisateur est alors mise à jour.

Nous sommes à la recherche de l’en-tête d’un fichier exécutable. Ces en-têtes sont utilisés par le système d’exploitation pour déterminer le type du fichier. Ainsi, l’en-tête d’un fichier exécutable Windows commence toujours par « 4D 5A » en hexadécimal, soit « MZ » en ASCII.

En étudiant la sortie de vidage du paramètre, nous pouvons voir qu’il ne contient pas ce que nous recherchons : impossible d’y trouver les valeurs « 4D 5A » ou « MZ ».

vidage

Le deuxième paramètre [esp+2c] ne contient pas non plus le malware : nous devons donc poursuivre l’exécution jusqu’à ce que nous le trouvions. Il nous faut cliquer sur Debug, puis exécuter le malware jusqu’au déclenchement d’un nouveau point d’arrêt à la fonction « VirtualAlloc ».

Nous suivons le même processus que précédemment, puis analysons les nouveaux paramètres. Cette fois-ci, l’appel à « VirtualAlloc » est passé par un appel au registre EBP. Le malware a encore une fois utilisé deux paramètres.

point d’arrêt de virtualalloc 4

En effectuant un clic droit sur [edi+54] et en suivant le contenu du paramètre dans la fenêtre de vidage, nous constatons qu’il contient cette fois un exécutable Windows, le malware dépacké !

vidage de virtualalloc

En faisant défiler la fenêtre vers le haut, nous voyons l’en-tête d’un fichier exécutable Windows : nous avons trouvé le malware dépacké. Notez les valeurs « 4D 5A » et « MZ », ainsi que la chaîne « This program cannot be run in DOS mode ».

mémoire tampon dépackée

Pour extraire le malware dépacké, faites un clic droit sur « MZ », puis choisissez Follow in Memory-Map.

follow in memory

La fenêtre montre où se trouve le malware dépacké en mémoire et les droits qui ont été alloués à cette zone de la mémoire.

carte mémoire

La capture ci-dessus indique l’adresse du malware en mémoire et le niveau de protection dont cette zone bénéficie. Trois indicateurs sont possibles : E (exécution), R (lecture) et W (écriture). Si le niveau de protection est « ERW », il y a de fortes chances qu’il s’agisse du malware, car la mémoire qui lui est allouée doit être exécutable et inscriptible.

Pour extraire le malware dépacké, faites un clic droit sur l’adresse mémoire et sélectionnez Dump Memory to File.

vidage mémoire

Choisissez l’emplacement dans lequel enregistrer le fichier dépacké, puis ouvrez ce fichier à l’aide d’un éditeur hexadécimal.

hxd1

Nous retrouvons l’en-tête du fichier que nous venons de vider de la mémoire. Toutefois, il ne ressemble pas à un fichier exécutable Windows, car l’en-tête ne commence pas par « 4D 5A » (affichage hexadécimal) et les valeurs ASCII ne commencent pas par « MZ ». La raison en est simple : le vidage du malware depuis la mémoire a entraîné l’ajout de code superflu au fichier.

Pour le nettoyer, appuyez sur Ctrl+F et recherchez la valeur « MZ ».

hxd2

Cliquez sur OK pour valider la recherche et trouver l’indicateur « MZ » et les valeurs « 4D 5A » qui lui sont associées.

hxd3

Pour nettoyer le fichier, sélectionnez l’ensemble du code hexadécimal précédant « 4D 5A ».

hxd4

Faites un clic droit sur les données hexadécimales en surbrillance, puis sélectionnez Delete.

hxd5

Nous disposons désormais d’un fichier propre correspondant parfaitement au malware dépacké.

hxd6

Maintenant que le malware est dépacké, nous pouvons commencer à analyser le code écrit par son auteur.

En deux articles, nous avons vu ce qu’était x64dbg et montré comment l’utiliser pour dépacker un malware. Dans mon prochain article, j’expliquerai ce qu’est la mémoire de la pile et son lien avec x64dbg, puis nous nous appuierons sur ces informations pour analyser le malware !

Il est essentiel de savoir dépacker et analyser un malware lors d’un incident de cybersécurité. Vous seriez probablement surpris de découvrir le risque de cyberattaque auquel votre organisation est exposée. Si votre équipe ne compte pas d’expert en malwares en son sein, il pourrait être intéressant de découvrir comment Varonis est en mesure de détecter les ransomwares afin de vous aider à doper vos cyberdéfenses.

Nous sommes Varonis.

Depuis 2005, nous protégeons les données les plus précieuses du monde des mains de vos ennemis grâce à notre plateforme de sécurité des données, leader sur le marché.

Comment fonctionne Varonis ?