
Windowsプロセスの仮想アドレス空間をヒルベルト曲線上に可視化します。
Clairvoyance (/klɛərˈvɔɪəns/; フランス語の clair は 明瞭 を、voyance は 視覚 を意味する) — Wikipedia より。
clairvoyance は、Windows 64ビットカーネル上で動作する64ビットプロセス全体のアドレス空間(ユーザーとカーネル)のページ保護をカラフルな可視化として生成します。
1次元の空間、すなわちアドレス空間を2次元の可視化に変換するために、ヒルベルト空間充填曲線 が使われています。上の画像の各色付きピクセルは、仮想メモリ内の4KBページのページ保護(UserRead、UserReadWrite など)を表しています。
アドレス空間は、WindDbg を使用して生成されたカーネルクラッシュダンプから、プロセスに関連する4レベルページテーブル階層を手動で解析することによって直接計算されます。
最後に、このプログラムは、2次元キャンバス上に表示するために必要なメタデータを含むファイルを出力し、特定の強調表示されたピクセルに対応する仮想アドレスを計算することもできます。
コンパイル済みバイナリはリリースセクションで入手できます。オンラインビューアは 0vercl0k.github.io/clairvoyance でもホストされています。
謝辞:
カーネルクラッシュダンプを生成するには、WinDbg と KDNet を .dump /f コマンドと共に使用することをお勧めします。
ダンプを取得したら、そのパスと、対象のページディレクトリの物理アドレスを clairvoyance に渡すことができます:
./clairvoyance <dump path> [<page dir pa>]
これにより、clairvoyance 拡張子のファイルが生成されます。このファイルは、0vercl0k.github.io/clairvoyance でブラウザで表示するか、ビューアがホストされている gh-pages ブランチをチェックアウトして表示できます。
CI は、Linux では clang++-11 を使用し、Windows では Microsoft の Visual Studio 2019 を使用して clairvoyance をビルドします。
自分でビルドするには、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 VM から生成されたカーネルクラッシュダンプで私が気付いた点です:
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 に感謝):
私がマイクロソフトに問い合わせたところ、「場合によってはカーネルがラージページでマッピングされる」ためこれは仕様であり、仮想化ベースの保護(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, ...)
これは、アドレス空間のいくつかの領域で見られるクールなパターンを紹介するセクションです。
ページヒープの割り当てとそのガードページは見た目がとてもクールで、簡単に見つけられます:
カーネルスタックも、そのサイズとガードページのおかげで、見た目がはっきりと認識できる形をしています:
私が見たダンプでは、カーネル内のシステムキャッシュ領域は星雲のように見えます:
Axel '0vercl0k' Souchet