Visualize the virtual address space of a Windows process on a Hilbert curve.
Clairvoyance (/klɛərˈvɔɪəns/; from French clair meaning clear and voyance meaning vision) from Wikipedia.
clairvoyance creates a colorful visualization of the page protection of an entire 64-bit process address space (user and kernel) running on a Windows 64-bit kernel.
To transform the 1 dimension space, that is the address space, into a 2 dimensions visualization, the hilbert space-filling curve is used. Each colored pixel on the above picture represents the page protection (UserRead, UserReadWrite, etc.) of a 4KB page in virtual memory.
Finally, the program program outputs a file with the metadata required to have it displayed on a two dimensional canvas as well as being able to calculate the virtual address corresponding to a specific highlighted pixel.
Shouts out to: - Alexandru Radocea and Georg Wicherski for the inspiration (see their BlackHat USA 2013 research: Visualizing Page Tables for Exploitation), - The Hacker's delight second edition's chapter 16 Hilbert's curve for providing the algorithms used.
Once the dump has been acquired you can pass its path to clairvoyance as well as the physical address of the page directory you are interested in:
This generates a file with the clairvoyance extension that you then can visualize in your browser at 0vercl0k.github.io/clairvoyance or by checking out the gh-pages branch which is where the viewer is hosted at.
To build it yourself you can use the scripts 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
The below are things I've noticed on a kernel crash-dump generated from an Hyper-V VM of 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 doesn't seem to be using huge pages (1GB) or at least I have not seen one being used in any of the dumps I collected.
Large pages are used in abundance to map some kernel executables like the Windows kernel nt for example:
kd> ? nt Evaluate expression: -8773703827456 = fffff805`36800000
VA:0xfffff80536800000, PA:0x2400000 (KernelReadWriteExec, Large, PML4E:0xd5745f80, PDPTE:0x42080a0, PDE:0x4209da0, PTE:0x0)
There are also a bunch of kernel read, write, executable pages that are not large pages, which was somewhat a surprise. I was aware that the kernel / hal could be mapped using large pages and that those were krwx. The reason for that is that 2MB is so large that it spans both executable and data sections; meaning the page has to be writeable and executable.
I contacted Microsoft which claimed that this is intended since “in some cases the kernel is mapped with large pages” and that this can be prevented by enabling virtualization based protection (VBS).
A bunch of large kernel memory sections are mapped against the same physical page (filled with zero):
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, ...)
Here is smaller one (the region is not completely contiguous, there are a few holes):
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, ...)
This is just a section showing off some of the cool patterns you can see in some regions of an address space.
Page heap allocations and their guard pages are pretty cool looking and easy to spot:
Kernel stacks also have a nice recognizable shape because of their size and guard pages:
The system cache region in the kernel seems to be looking like a nebula in the dumps I have seen:
Axel '0vercl0k' Souchet