
Визуализируйте виртуальное адресное пространство процесса Windows на кривой Гильберта.
Clairvoyance (/klɛərˈvɔɪəns/; от французского clair, означающего ясный, и voyance, означающего видение) из Википедии.
clairvoyance создает красочную визуализацию защиты страниц всего 64-битного адресного пространства процесса (user и kernel), работающего в 64-битном ядре Windows.
Чтобы преобразовать одномерное пространство, то есть адресное пространство, в двумерную визуализацию, используется пространственно-заполняющая кривая Гильберта. Каждый цветной пиксель на изображении выше представляет защиту страницы (UserRead, UserReadWrite и т.д.) для 4KB страницы в виртуальной памяти.
Адресное пространство напрямую вычисляется путем ручного разбора четырехуровневой иерархии таблиц страниц, связанной с процессом, из аварийного дампа ядра, созданного с помощью WindDbg.
Наконец, программа выводит файл с метаданными, необходимыми для отображения на двумерном холсте, а также для возможности вычислить виртуальный адрес, соответствующий конкретному подсвеченному пикселю.
Скомпилированные двоичные файлы доступны в разделе релизов. Онлайн-просмотрщик также размещен на 0vercl0k.github.io/clairvoyance.
Благодарности:
Для создания аварийного дампа ядра рекомендуется использовать WinDbg, KDNet с командой .dump /f.
После получения дампа вы можете передать его путь в clairvoyance, а также физический адрес интересующего вас каталога страниц:
./clairvoyance <dump path> [<page dir pa>]
Это создает файл с расширением clairvoyance, который затем можно просмотреть в браузере на 0vercl0k.github.io/clairvoyance или перейдя в ветку gh-pages, где размещен просмотрщик.
CI собирает clairvoyance на Linux с помощью clang++-11 и на Windows с помощью Microsoft Visual studio 2019.
Чтобы собрать его самостоятельно, вы можете использовать скрипты в 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
Ниже приведены наблюдения, сделанные на аварийном дампе ядра, созданном на основе виртуальной машины Windows под Hyper-V:
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 не использует гигантские страницы (1GB) или, по крайней мере, я не видел их использования ни в одном из собранных мной дампов.
Большие страницы в большом количестве используются для отображения некоторых исполняемых файлов ядра, например, ядра Windows nt:
kd> ? nt
Evaluate expression: -8773703827456 = fffff805`36800000
VA:0xfffff80536800000, PA:0x2400000 (KernelReadWriteExec, Large, PML4E:0xd5745f80, PDPTE:0x42080a0, PDE:0x4209da0, PTE:0x0)
Также есть множество страниц ядра с правами чтения, записи и исполнения, которые не являются большими страницами, что было несколько неожиданно. Я знал, что ядро / hal могут быть отображены с использованием больших страниц и что они имеют права krwx. Причина в том, что 2MB — это так много, что она охватывает как исполняемые, так и данные секции; то есть страница должна быть доступна для записи и исполнения.
Единственное публичное упоминание об этом, которое я смог найти, находится в этом блог-посте (спасибо `Ivan):
Я связался с Microsoft, и там заявили, что это предусмотрено, поскольку «в некоторых случаях ядро отображается с помощью больших страниц», и что это можно предотвратить, включив защиту на основе виртуализации (VBS).
Большое количество участков памяти ядра отображается на одну и ту же физическую страницу (заполненную нулями):
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, ...)
Вот пример поменьше (область не полностью непрерывна, есть несколько дыр):
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, ...)
Это просто раздел, демонстрирующий некоторые интересные узоры, которые можно увидеть в некоторых областях адресного пространства.
Выделения Page heap и их защитные страницы выглядят довольно эффектно, и их легко обнаружить:
Стеки ядра также имеют характерную узнаваемую форму из-за своего размера и защитных страниц:
Область системного кэша в ядре в просмотренных мной дампах выглядит как туманность:
Axel '0vercl0k' Souchet