
Windows 프로세스의 가상 주소 공간을 힐베르트 곡선으로 시각화합니다.
Clairvoyance (/klɛərˈvɔɪəns/; 프랑스어 clair는 맑은, voyance는 투시를 의미) — Wikipedia에서.
clairvoyance는 Windows 64비트 커널에서 실행되는 전체 64비트 프로세스 주소 공간(사용자 및 커널)의 페이지 보호를 화려한 시각화로 생성합니다.
주소 공간이라는 1차원 공간을 2차원 시각화로 변환하기 위해 hilbert 공간 채움 곡선이 사용됩니다. 위 그림의 각 색상 픽셀은 가상 메모리의 4KB 페이지에 대한 페이지 보호(UserRead, UserReadWrite 등)를 나타냅니다.
주소 공간은 WindDbg를 사용해 생성된 커널 크래시 덤프에서 프로세스와 연결된 4단계 페이지 테이블 계층을 수동으로 파싱하여 직접 계산됩니다.
마지막으로, 이 프로그램은 2차원 캔버스에 표시하는 데 필요한 메타데이터가 포함된 파일을 출력하며, 특정 강조 표시된 픽셀에 해당하는 가상 주소를 계산할 수도 있습니다.
컴파일된 바이너리는 releases 섹션에서 사용할 수 있습니다. 온라인 뷰어는 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
아래는 Hyper-V VM의 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는 거대 페이지(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(가상화 기반 보호)를 활성화하면 이를 방지할 수 있다고 주장했습니다.
많은 대형 커널 메모리 섹션이 동일한 물리 페이지(0으로 채워진)에 매핑되어 있습니다:
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