
Visualizza lo spazio degli indirizzi virtuali di un processo Windows su una curva di Hilbert.
Clairvoyance (/klɛərˈvɔɪəns/; dal francese clair che significa chiaro e voyance che significa visione) da Wikipedia.
clairvoyance crea una visualizzazione colorata della protezione delle pagine dell'intero spazio di indirizzi di un processo a 64 bit (utente e kernel) in esecuzione su un kernel Windows a 64 bit.
Per trasformare lo spazio unidimensionale, cioè lo spazio degli indirizzi, in una visualizzazione bidimensionale, viene utilizzata la curva di Hilbert che riempie lo spazio. Ogni pixel colorato nell'immagine qui sopra rappresenta la protezione della pagina (UserRead, UserReadWrite, ecc.) di una pagina da 4KB nella memoria virtuale.
Lo spazio degli indirizzi viene calcolato direttamente analizzando manualmente la gerarchia di tabelle delle pagine a quattro livelli associata a un processo da un kernel crash-dump generato utilizzando WindDbg.
Infine, il programma genera un file con i metadati necessari per visualizzarlo su una tela bidimensionale e per poter calcolare l'indirizzo virtuale corrispondente a uno specifico pixel evidenziato.
I binari compilati sono disponibili nella sezione releases. Un visualizzatore online è anche ospitato su 0vercl0k.github.io/clairvoyance.
Un ringraziamento a:
Per generare il kernel crash dump si consiglia di utilizzare WinDbg, KDNet con il comando .dump /f.
Una volta ottenuto il dump, puoi passare il suo percorso a clairvoyance insieme all'indirizzo fisico della directory delle pagine che ti interessa:
./clairvoyance <dump path> [<page dir pa>]
Questo genera un file con estensione clairvoyance che puoi poi visualizzare nel tuo browser su 0vercl0k.github.io/clairvoyance oppure consultando il branch gh-pages, dove è ospitato il visualizzatore.
La CI compila clairvoyance su Linux usando clang++-11 e su Windows usando il Visual studio 2019 di Microsoft.
Per compilarlo da solo puoi usare gli script in 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
Quella che segue sono cose che ho notato su un kernel crash-dump generato da una VM Hyper-V di 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 non sembra utilizzare le huge pages (1GB) o almeno non ne ho viste usare in nessuno dei dump che ho raccolto.
Le large pages sono usate in abbondanza per mappare alcuni eseguibili del kernel come il kernel Windows nt, per esempio:
kd> ? nt
Evaluate expression: -8773703827456 = fffff805`36800000
VA:0xfffff80536800000, PA:0x2400000 (KernelReadWriteExec, Large, PML4E:0xd5745f80, PDPTE:0x42080a0, PDE:0x4209da0, PTE:0x0)
Ci sono anche un bel po' di pagine kernel in lettura, scrittura, esecuzione che non sono large pages, il che è stata una sorpresa. Sapevo che il kernel / hal potessero essere mappati usando large pages e che queste fossero krwx. Il motivo è che 2MB è così grande da attraversare sia le sezioni eseguibili che quelle dei dati; ciò significa che la pagina deve essere scrivibile ed eseguibile.
L'unica menzione pubblica di questo che sono riuscito a trovare è in questo blogpost (grazie `Ivan):
Ho contattato Microsoft che ha affermato che questo è voluto poiché "in alcuni casi il kernel è mappato con large pages" e che può essere prevenuto abilitando la protezione basata sulla virtualizzazione (VBS).
Un sacco di grandi sezioni di memoria del kernel sono mappate sulla stessa pagina fisica (riempita con zeri):
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, ...)
Ecco una più piccola (la regione non è completamente contigua, ci sono alcuni buchi):
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, ...)
Questa è solo una sezione per mostrare alcuni dei bei pattern che si possono vedere in alcune regioni di uno spazio di indirizzi.
Le allocazioni page heap e le loro guard page sono piuttosto belle da vedere e facili da individuare:
Anche gli stack del kernel hanno una bella forma riconoscibile grazie alle loro dimensioni e alle guard page:
La regione della cache di sistema nel kernel sembra assomigliare a una nebulosa nei dump che ho visto:
Axel '0vercl0k' Souchet