# Présentation de DRAKVUF : analyser un malware depuis l'hyperviseur, sans agent dans la VM

**Catégorie :** DRAKVUF

---

## Résumé

[DRAKVUF](https://github.com/tklengyel/drakvuf) analyse un malware pendant qu'il tourne, depuis l'hyperviseur Xen, sans rien installer dans la VM. Le malware ne trouve aucun outil d'analyse dans son système, aucun pilote, aucun processus suspect, et c'est tout l'intérêt. Ce billet explique le principe (altp2m et les points d'arrêt invisibles), les plugins, l'injection de programmes, la ligne de commande, comment on prépare une VM et son profil, les règles que je m'impose au lab, et ce que DRAKVUF ne sait pas faire. Les correctifs que j'ai envoyés au projet sont dans [un billet à part](index.html?w=drakvuf-contributions.md).

## 1. Le principe

Une sandbox classique installe un agent dans la VM pour observer le malware. Le malware peut le détecter, le contourner, ou simplement refuser de tourner. DRAKVUF fait le contraire : il observe depuis le dom0 de Xen, à travers [LibVMI](index.html?w=libvmi-presentation.md), et il intervient dans l'exécution par des mécanismes du processeur que le guest ne peut pas voir.

Le cœur, c'est **altp2m**. Xen peut maintenir plusieurs tables de traduction (EPT) pour une même VM, plusieurs « vues » de sa mémoire physique. DRAKVUF s'en sert pour poser des points d'arrêt invisibles : dans une vue, une page de code contient une instruction `int3` à l'adresse surveillée ; dans une autre, la page est intacte. Le guest exécute sur la vue modifiée ; quand il lit sa propre mémoire (un malware qui vérifie son intégrité, par exemple), il voit la vue intacte. Quand l'`int3` est atteint, Xen remet la main à DRAKVUF, qui lit les registres et la pile, émet un événement, puis fait exécuter l'instruction d'origine en pas à pas sur une troisième vue avant de rebasculer. Tout ça sans qu'aucune page visible du guest ne change.

Les points d'arrêt sont posés sur des fonctions dont DRAKVUF connaît l'adresse par le profil du noyau : `NtCreateUserProcess`, `NtWriteFile`, les appels système, ou des fonctions de DLL dans les processus (via `libusermode`, qui attend que la DLL soit chargée pour poser le hook). Un `ReturnHook` est un point d'arrêt posé sur l'adresse de retour d'un appel, pour lire son résultat.

## 2. Les plugins

Chaque plugin surveille un aspect et produit une ligne par événement (texte, CSV ou JSON). Ceux que j'utilise le plus :

| Plugin | Ce qu'il voit |
|---|---|
| `procmon` | création et fin de processus, ligne de commande, parent |
| `syscalls` | chaque appel système, avec ses arguments (très bavard) |
| `filetracer` | ouverture, lecture, écriture, suppression de fichiers |
| `regmon` | lectures et écritures du registre |
| `apimon` | appels d'API dans les processus, sur une liste de fonctions choisie |
| `rpcmon` | appels RPC |
| `codemon` | code exécuté hors des modules connus (injection, shellcode) |
| `memdump` | vidage de régions mémoire sur certains événements |
| `fileextractor` | copie des fichiers écrits ou supprimés par le guest (nécessite `-D <dossier>`) |
| `dkommon` | objets noyau cachés (processus, pilotes, services) |
| `socketmon` | connexions réseau vues depuis le noyau |
| `hidsim` | simule souris et clavier pour que le malware se réveille |
| `hidevm` | masque les signes de VM (requêtes WMI, compteur de ticks, sonde thermique) |
| `exploitmon`, `bsodmon`, `crashmon` | exceptions, écrans bleus, crashs |
| `etwmon`, `wmimon`, `tlsmon`, `ssdtmon`, `poolmon` | ETW, WMI, clés TLS, table des appels système, allocations de pool |

Il y en a une quarantaine. Sans `-a`, DRAKVUF les active **tous**, ce qui est rarement ce qu'on veut.

## 3. L'injection

DRAKVUF peut lancer un programme dans la VM sans agent, en détournant un processus existant au moment où il fait un appel système : il sauvegarde les registres, fait exécuter `CreateProcess` (ou autre) avec ses propres arguments, récupère le résultat, et restaure. Les méthodes (`-m`) : `createproc` (lancer un exécutable), `shellexec`, `shellcode`, `readfile` et `writefile` (copier un fichier dans un sens ou dans l'autre), `terminateproc`. Le processus cible se donne par `-i <pid>`, en pratique `explorer.exe`, et la commande par `-e`. Une leçon du lab : trois injections `createproc` successives dans le même `explorer.exe` le font planter, donc une injection par démarrage, et un redémarrage propre entre deux tests.

## 4. La ligne de commande

```
drakvuf -r win11-25h2.json -d win11-25h2 -a procmon -a filetracer -t 60 -o json
```

- `-r` : profil JSON du noyau de **ce** build. `-d` : nom de la VM Xen. `-a` : plugin à activer (répétable), `-x` : plugin à exclure. `-t` : durée en secondes. `-o` : format de sortie.
- `-k <kpgd>` : donner le DTB du noyau à la main, ce qui évite à LibVMI de le chercher (mais la valeur change à chaque démarrage).
- `-i`, `-e`, `-m` : l'injection. `-D` : dossier de sortie pour `fileextractor` et `memdump`.
- `--userhook-injection-mode` : comment `libusermode` pose ses hooks (le mode par défaut attend plusieurs appels système du même processus avant de converger). `--userhook-target-process <nom>` : ne hooker que ce processus et ses descendants.
- `-v` : traces de debug, dans un build compilé en debug.
- Ctrl+C pour arrêter. DRAKVUF retire ses points d'arrêt et relâche la VM. Un `drakvuf ... | head` tué par SIGPIPE ne le fait pas, et laisse le domaine en pause.

Si l'initialisation échoue, DRAKVUF ne le dit pas : il tourne jusqu'au timeout, sort 0 événement et un code retour 0. Il faut toujours regarder le nombre d'événements.

## 5. Préparer une VM

La VM est une VM Xen HVM ordinaire, avec quelques options :
- `altp2m=1` (indispensable), et `ept=ad=0` dans les options de démarrage de Xen (voir [le billet sur le crash reason 49](index.html?w=drakvuf-xen-reason49-ept-ad0.md)).
- Pour ne pas se faire repérer trop vite : `viridian=0`, `cpuid="host,hypervisor=0"`, `xen_platform_pci=0`, un SMBIOS de vraie machine (ici un Dell OptiPlex 7090), un disque IDE et une carte e1000 plutôt que les pilotes paravirtualisés. Ça ne cache pas tout : le modèle de disque QEMU reste visible par WMI, et le timing trahit toujours une VM.
- Un réseau isolé, sans sortie vers Internet.
- Un snapshot propre du disque, restauré avant chaque analyse.

Le profil JSON se génère depuis le `ntoskrnl.exe` de la VM : extraction du fichier (guestfish, ou `qemu-nbd` sur 24H2 où il est compressé), lecture du GUID du PDB, téléchargement du PDB chez Microsoft, conversion en JSON. Un profil vaut pour un build exact. Les plugins qui hookent des DLL (`hidevm` avec `fastprox.dll`) ont en plus leurs propres offsets, à jour ou non selon le build.

Sur Windows 11, TPM et Secure Boot se contournent à l'installation (clés `LabConfig`), et il faut compter avec VBS et HVCI activés par défaut, qui renforcent le KVA shadowing et compliquent l'attache (voir [LibVMI](index.html?w=libvmi-presentation.md), section 3).

## 6. Les règles que je m'impose

- Aucun agent dans la VM, jamais. Si un test en a besoin, c'est le test qui est mauvais.
- Une seule VM allumée à la fois pendant les mesures.
- Attendre que Windows ait fini de démarrer avant d'attacher DRAKVUF : 15 s au minimum sur ces machines, et la bonne façon est de regarder l'état de la VM, pas l'horloge.
- Jamais conclure « 0 événement » sans avoir lu `xl dmesg`, le journal de la VM, et le code du plugin.
- Un binaire reconstruit proprement avant toute bissection ; un build incrémental a déjà faussé une conclusion.
- Un seul DRAKVUF par LibVMI : ne jamais mélanger un LibVMI système et un DRAKVUF compilé contre son sous-module, les structures n'ont pas la même taille.

## 7. Ce que DRAKVUF ne fait pas

Il ne détecte pas qu'un guest redémarre : il sort une rafale d'erreurs altp2m et continue. Il ne sait pas que l'initialisation a échoué. Il ne hooke pas un processus déjà en cours quand on l'attache, par choix de conception : chaque analyse part d'une ardoise propre. Et il ne réveille pas le malware à votre place : un échantillon qui attend un clic, une connexion réseau ou une date ne fera rien, `hidsim` et un réseau simulé aident, pas plus.

## Sources

- [DRAKVUF](https://github.com/tklengyel/drakvuf) sur GitHub, `drakvuf --help`, et le code des plugins dans `src/plugins/`.
- Le site du projet, [drakvuf.com](https://drakvuf.com), pour l'installation.
