Reverse engineering
Introduction
Présentation
Le reverse engineering (ou rétro-ingénierie en français) consiste à étudier un objet (dans notre cas un malware) pour comprendre son fonctionnement. En informatique, cela se traduit par l’analyse du code machine d’un programme, dans notre cas un malware. Étant donné que les malwares ne sont pas diffusés avec leur code source et qu’il n’est pas possible de retrouver les codes des malwares développés en C ou en C++, il est nécessaire de faire appel au reverse engineering pour étudier leur fonctionnement interne. L’analyste étudiera le code assembleur du malware, fonction après fonction. Ce code assembleur est disponible après désassemblage du binaire.
Le code assembleur n’est pas aussi facile à lire que du code source. En effet, c’est un langage bas niveau qui manipule directement les instructions CPU et la mémoire physique.
Nous allons principalement nous intéresser à l’assembleur x86 (32 bits), même si une courte section présentera les principales différences entre le x86 et le x64 (64 bits) d’un point de vue rétro-ingénierie. Aujourd’hui, 80 % des malwares sont compilés en 32 bits, ceci afin de pouvoir impacter le plus de machines possible (les systèmes Windows 64 bits supportent les binaires 32 bits, mais l’inverse n’est pas vrai).
Ce chapitre expliquera comment lire et interpréter l’assembleur, les outils utilisables pour mener l’analyse et des astuces pour la faciliter.
Législation
Dans de nombreux pays, le reverse engineering est encadré par des lois. De nombreuses utilisations peuvent être faites de cette discipline :
-
L’espionnage industriel : certaines sociétés utilisent...
Qu’est-ce qu’un processus Windows ?
Introduction
Lorsqu’on exécute un processus sous Windows, le système d’exploitation va automatiquement créer un espace mémoire pour celui-ci et un premier thread. Chaque processus en cours d’exécution dispose d’une structure le décrivant, appelée PEB (Process Environment Block). Chaque processus dispose d’un ou plusieurs threads. Un thread est un fil d’exécution. Les threads sont exécutés en parallèle. Chaque thread dispose de sa propre pile (stack, cf. chapitre Techniques d’obfuscation) et d’une structure le définissant appelée TEB (Thread Environment Block). Les threads peuvent accéder à la mémoire du processus. Voici un schéma décrivant un processus :
Process Environment Block
Il est possible de lire le contenu du PEB d’un processus. Voici un exemple de PEB du processus cmd.exe vu par le débogueur de Microsoft : WinDbg. L’adresse mémoire à laquelle se trouve la structure PEB est stockée dans $PEB :
0:001> r $PEB
$peb=0000000301292000
À partir de cette adresse, nous pouvons vérifier le contenu de la structure PEB :
0:001> dt _PEB 0000000301292000
ntdll!_PEB
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
+0x002 BeingDebugged : 0x1 ''
+0x003 BitField : 0x4 ''
+0x003 ImageUsesLargePages : 0y0
+0x003 IsProtectedProcess : 0y0
+0x003 IsImageDynamicallyRelocated : 0y1
+0x003 SkipPatchingUser32Forwarders : 0y0 ...
Assembleur x86
Registres
Le x86 est une architecture où le processeur utilise principalement des registres 32 bits afin de stocker ses informations. Chaque registre contient un nombre codé sur 32 bits, mais ce nombre peut aussi être vu comme deux nombres de 16 bits ou 4 nombres de 8 bits. Dans un souci de compréhension, nous allons illustrer ce point par un exemple.
Le nombre hexadécimal 0xC0DEBA5E est un entier 32 bits. En effet, il peut être représenté par les 32 bits suivants :
Hexadécimal |
C |
0 |
D |
E |
B |
A |
5 |
E |
Binaire |
1100 |
0000 |
1101 |
1110 |
1011 |
1010 |
0101 |
1110 |
Il peut être vu comme deux entiers sur 16 bits : 0xC0DE et 0xBA5E, ou quatre entiers sur 8 bits : 0xC0, 0xDE, 0xBA et 0x5E. Il est important de s’habituer à cette petite gymnastique, car l’assembleur fait souvent un usage abusif de ces différentes représentations.
Pour faciliter les explications, on utilise communément des termes spécifiques pour distinguer ces nombres de différentes tailles. Un octet est un nombre sur 8 bits, un mot est un nombre sur 16 bits, soit 2 octets, un double est un nombre sur 32 bits, soit 2 mots ou 4 octets.
Les architectures x86 comportent principalement 16 registres différents classés en cinq types : les registres généraux, les registres d’index, les registres de pointeurs, les registres de segments et le registre de drapeaux (ou flags).
Registres généraux
Il existe quatre registres de ce type : EAX, EBX, ECX et EDX.
Ces registres font 32 bits et peuvent être décomposés en sous-registres plus petits. Dans ce cas, leur notation change. Voici un exemple pour EAX :
Les chiffres en bas du chemin correspondent aux bits du registre. Le E présent au debut de chaque registre correspond à Extended. Le 32 bits étant une extension du 16 bits...
Assembleur x64
Registres
Dans l’architecture x64, les registres ont une taille de 64 bits. Les registres commencent par un R. Par exemple, la version 64 bits du registre EAX est RAX (même si EAX existe toujours et représente 32 bits). Voici le schéma :
Il existe, en plus des registres cités dans la section Assembleur x86, de nouveaux registres allant de R8 à R15.
Paramètres des fonctions
Nous avons vu que dans l’architecture x86, les paramètres des fonctions étaient passés via la stack et l’instruction PUSH. En 64 bits, le passage des arguments est différent :
-
Le premier argument est passé via le registre RCX.
-
Le deuxième argument est passé via le registre RDX.
-
Le troisième argument est passé via le registre R8.
-
Le quatrième argument est passé via le registre R9.
-
La suite des arguments (s’il y en a) est passée via la stack comme pour l’architecture x86.
Analyse statique
Présentation
L’analyse statique consiste à analyser le code assembleur sans exécuter le binaire associé. Par cette méthode, il est possible d’analyser n’importe quel type de binaire sur n’importe quelle architecture. Il n’y a pas non plus de risque d’infection par le malware, celui-ci n’étant pas exécuté. L’avantage de l’analyse statique est que justement elle ne dépend pas de l’exécution. Ainsi, la plupart des comportements du binaire peuvent être déduits statiquement, même ceux difficiles à observer par l’exécution. Par exemple, le comportement d’un RAT dépend des commandes lancées par l’attaquant. Sans interaction de l’attaquant, il est difficile d’observer le comportement du RAT lors de son exécution. L’analyse statique n’est pas soumise à cette limitation.
Pour réaliser une analyse statique, il est nécessaire d’utiliser un désassembleur afin de décoder le code machine du malware en langage assembleur. Ce logiciel doit permettre de commenter les instructions, de renommer les variables, les fonctions ou encore de présenter une vue graphique du flux d’exécution. Le travail dans le cas d’une analyse statique consiste à commenter les instructions, à comprendre les fonctions ainsi que leurs arguments afin de pouvoir comprendre le flux d’exécution du malware et de savoir ce qu’il fait réellement sur la machine infectée.
Ghidra
a. Présentation
Ghidra est un outil d’analyse statique rendu public par la NSA (Agence nationale de sécurité des États-Unis) début 2019. Il est disponible en téléchargement à cette adresse :...
Analyse dynamique
Présentation
Contrairement à l’analyse statique, l’analyse dynamique consiste à étudier les actions du binaire pendant qu’il est train de s’exécuter. Il est important de noter que, dans ce cas, le binaire est réellement exécuté et que la machine sur laquelle il est exécuté sera infectée par le malware en cours d’analyse. Il est donc primordial de travailler dans une machine virtuelle.
Pour réaliser une analyse dynamique, l’analyste a besoin d’un débogueur. Un débogueur permet d’exécuter un binaire instruction après instruction, il permet également de placer des points d’arrêt (ou breakpoints) afin de stopper l’exécution du binaire et de consulter son état. Dans cette section, nous utiliserons deux débogueurs : x64dbget WinDbg.
Chaque analyste a sa propre manière de travailler avec son débogueur, l’important est de se familiariser avec celui-ci. C’est un incontournable dans la trousse à outils d’une personne souhaitant analyser des malwares
x64dbg
Présentation
X64dbg est un débogueur 32 bits et 64 bits pour Windows. Il est gratuitement téléchargeable à l’adresse suivante : https://x64dbg.com/. Ce débogueur permet de suivre facilement l’exécution d’un programme sous Windows. Il permet de voir les instructions exécutées, l’état de la mémoire et des registres. Il permet également de placer des points d’arrêt à des instructions particulières, lors d’accès à certaines zones mémoire ou lors de l’exécution de fonctions spécifiques. Chacune de ces fonctionnalités sera décrite dans cette...