
Visualisez l'espace d'adressage virtuel d'un processus Windows sur une courbe de Hilbert.
Clairvoyance (/klɛərˈvɔɪəns/; du français clair signifiant clear et voyance signifiant vision), d'après Wikipedia.
clairvoyance crée une visualisation colorée de la protection des pages de l'ensemble de l'espace d'adressage d'un processus 64 bits (utilisateur et noyau) s'exécutant sur un noyau Windows 64 bits.
Pour transformer l'espace à une dimension, c'est-à-dire l'espace d'adressage, en une visualisation à deux dimensions, la courbe de remplissage d'espace de Hilbert est utilisée. Chaque pixel coloré de l'image ci-dessus représente la protection de page (UserRead, UserReadWrite, etc.) d'une page de 4 Ko en mémoire virtuelle.
L'espace d'adressage est directement calculé en analysant manuellement la hiérarchie de tables de pages à quatre niveaux associée à un processus à partir d'un crash-dump du noyau généré à l'aide de WindDbg.
Enfin, le programme produit un fichier contenant les métadonnées nécessaires pour l'afficher sur un canevas bidimensionnel, ainsi que pour calculer l'adresse virtuelle correspondant à un pixel spécifique mis en surbrillance.
Des binaires compilés sont disponibles dans la section releases. Un visualiseur en ligne est également hébergé à 0vercl0k.github.io/clairvoyance.
Remerciements à :
Pour générer le crash dump du noyau, il est recommandé d'utiliser WinDbg, KDNet avec la commande .dump /f.
Une fois le dump obtenu, vous pouvez passer son chemin à clairvoyance ainsi que l'adresse physique du répertoire de pages qui vous intéresse :
./clairvoyance <dump path> [<page dir pa>]
Cela génère un fichier avec l'extension clairvoyance que vous pouvez ensuite visualiser dans votre navigateur sur 0vercl0k.github.io/clairvoyance ou en consultant la branche gh-pages qui est l'endroit où le visualiseur est hébergé.
Le CI compile clairvoyance sur Linux à l'aide de clang++-11 et sur Windows à l'aide de Visual studio 2019 de Microsoft.
Pour le compiler vous-même, vous pouvez utiliser les scripts dans build/ :
(base) clairvoyance\build>build-msvc.bat
(base) clairvoyance\build>cmake ..
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19042.
-- Configuring done
-- Generating done
-- Build files have been written to: clairvoyance/build
(base) clairvoyance\build>cmake --build . --config RelWithDebInfo
Microsoft (R) Build Engine version 16.8.2+25e4d540b for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
clairvoyance.vcxproj -> clairvoyance\build\RelWithDebInfo\clairvoyance.exe
Building Custom Rule clairvoyance/CMakeLists.txt
Ce qui suit regroupe des choses que j'ai remarquées sur un crash-dump du noyau généré à partir d'une VM Hyper-V de Windows :
kd> vertarget
Windows 10 Kernel Version 18362 UP Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Edition build lab: 18362.1.amd64fre.19h1_release.190318-1202
Machine Name:
Kernel base = 0xfffff805`36800000 PsLoadedModuleList = 0xfffff805`36c432f0
Debug session time: Sat Jul 25 10:00:19.637 2020 (UTC - 8:00)
System Uptime: 0 days 0:18:53.609
Windows ne semble pas utiliser de pages énormes (1 Go), ou du moins je n'en ai vu aucune dans les dumps que j'ai collectés.
Les grandes pages sont utilisées en abondance pour mapper certains exécutables du noyau comme le noyau Windows nt par exemple :
kd> ? nt
Evaluate expression: -8773703827456 = fffff805`36800000
VA:0xfffff80536800000, PA:0x2400000 (KernelReadWriteExec, Large, PML4E:0xd5745f80, PDPTE:0x42080a0, PDE:0x4209da0, PTE:0x0)
Il y a aussi un tas de pages noyau en lecture, écriture et exécution qui ne sont pas des grandes pages, ce qui était un peu surprenant. Je savais que le noyau / hal pouvait être mappé à l'aide de grandes pages et que celles-ci étaient krwx. La raison en est qu'une page de 2 Mo est si grande qu'elle couvre à la fois les sections exécutables et de données ; cela signifie que la page doit être accessible en écriture et en exécution.
La seule mention publique que j'ai pu trouver se trouve dans ce blogpost (merci `Ivan) :
J'ai contacté Microsoft, qui a affirmé que c'était voulu car « dans certains cas, le noyau est mappé avec de grandes pages » et que cela peut être évité en activant la protection basée sur la virtualisation (VBS).
Un tas de grandes sections mémoire du noyau sont mappées sur la même page physique (remplie de zéros) :
VA:0xffffc27ef4401000, PA:0x4200000 (KernelRead, Normal, ...)
VA:0xffffc27ef4402000, PA:0x4200000 (KernelRead, Normal, ...)
VA:0xffffc27ef4403000, PA:0x4200000 (KernelRead, Normal, ...)
...
VA:0xffffc27ef63fb000, PA:0x4200000 (KernelRead, Normal, ...)
VA:0xffffc27ef63fc000, PA:0x4200000 (KernelRead, Normal, ...)
VA:0xffffc27ef63fd000, PA:0x4200000 (KernelRead, Normal, ...)
VA:0xffffc27ef63fe000, PA:0x4200000 (KernelRead, Normal, ...)
VA:0xffffc27ef63ff000, PA:0x4200000 (KernelRead, Normal, ...)
En voici un plus petit (la région n'est pas complètement contiguë, il y a quelques trous) :
VA:0xffffc27ed2201000, PA:0x4300000 (KernelRead, Normal, ...)
VA:0xffffc27ed2202000, PA:0x4300000 (KernelRead, Normal, ...)
VA:0xffffc27ed2203000, PA:0x4300000 (KernelRead, Normal, ...)
...
VA:0xffffc27ed25fc000, PA:0x4300000 (KernelRead, Normal, ...)
VA:0xffffc27ed25fd000, PA:0x4300000 (KernelRead, Normal, ...)
VA:0xffffc27ed25fe000, PA:0x4300000 (KernelRead, Normal, ...)
VA:0xffffc27ed25ff000, PA:0x4300000 (KernelRead, Normal, ...)
Ce n'est qu'une section qui montre quelques-uns des motifs intéressants que l'on peut voir dans certaines régions d'un espace d'adressage.
Les allocations Page heap et leurs pages de garde sont assez sympas à voir et faciles à repérer :
Les piles du noyau ont aussi une forme bien reconnaissable grâce à leur taille et à leurs pages de garde :
La région du cache système dans le noyau semble ressembler à une nébuleuse dans les dumps que j'ai vus :
Axel '0vercl0k' Souchet