将 PEB 移出页面时映射符号
若要加载符号,调试器会查看操作系统加载的模块列表。 指向用户模式模块列表的指针是存储在进程环境块中的项之一, (PEB) 。
为了回收内存,内存管理器可能会分页出用户模式数据,为其他进程或内核模式组件提供空间。 分页的用户模式数据可能包括 PEB 数据结构。 如果没有此数据结构,调试器无法确定要为哪些映像加载符号。
注意 这仅影响用户模式模块的符号文件。 内核模式模块和符号不受影响,因为它们在不同的列表中进行跟踪。
假设用户模式模块已映射到当前进程,并且你想要修复该模块的符号。 在模块的虚拟地址范围内查找任何地址。 例如,假设一个模块映射到包含地址 7f78e9e000F 的虚拟地址范围。 输入以下命令。
3: kd> !vad 7f78e9e000F 1
命令输出显示有关模块的虚拟地址描述符 (VAD) 的信息。 命令输出还包括可用于加载模块符号的 Reload 命令字符串。 重载命令字符串包括记事本模块的起始地址 (000007f7'8e9e0000) 和大小 (32000) 。
VAD @ fffffa80056fb960
...
Reload command: .reload notepad.exe=000007f7`8e9e0000,32000
若要加载符号,请输入重载命令字符串中提供的命令。
.reload notepad.exe=000007f7`8e9e0000,32000
下面是使用略有不同的技术的另一个示例。 该示例演示如何在 PEB 分页时使用 !vad 扩展映射符号。基本思路是查找相关 DLL 的起始地址和大小,以便可以使用 .reload 命令加载必要的符号。 假设当前进程的地址0xE0000126'01BA0AF0,并且你想要修复它的符号。 首先,使用 !process 命令获取虚拟地址描述符 (VAD) 根地址:
kd> !process e000012601ba0af0 1
PROCESS e000012601ba0af0
SessionId: 2 Cid: 0b50 Peb: 6fbfffde000 ParentCid: 0efc
DirBase: 079e8461 ObjectTable: e000000600fbceb0 HandleCount: 360.
Image: explorer.exe
VadRoot e000012601a35e70 Vads 201 Clone 0 Private 917. Modified 2198. Locked 0.
...
然后使用 !vad 扩展列出与进程关联的 VAD 树。 标记为“EXECUTE_WRITECOPY”的 VAD 属于代码模块。
kd> !vad e000012601a35e70
VAD level start end commit
...
e0000126019f9790 ( 6) 3fff0 3fff7 -1 Private READONLY
e000012601be1080 ( 7) 37d9bd30 37d9bd3e 2 Mapped Exe EXECUTE_WRITECOPY <-- these are DLLs
e000012600acd970 ( 5) 37d9bec0 37d9bece 2 Mapped Exe EXECUTE_WRITECOPY
e000012601a5cba0 ( 7) 37d9c910 37d9c924 2 Mapped Exe EXECUTE_WRITECOPY
...
然后再次使用 !vad 扩展查找保存所需 DLL 的分页内存的起始地址和大小。 这确认你已找到正确的 DLL:
kd> !vad e000012601be1080 1
VAD @ e000012601be1080
Start VPN: 37d9bd30 End VPN: 37d9bd3e Control Area: e00001260197b8d0
First ProtoPte: e0000006013e00a0 Last PTE fffffffffffffffc Commit Charge 2 (2.)
Secured.Flink 0 Blink 0 Banked/Extend: 0
File Offset 0
ImageMap ViewShare EXECUTE_WRITECOPY
...
File: \Windows\System32\ExplorerFrame.dll
“启动 VPN”字段(在本例中为0x37D9BD30)指示起始虚拟页码。 必须将其乘以页面大小,从而将其转换为实际地址。 可以使用 ? (Evaluate Expression) 命令将此值乘以 0x2000,这是示例基于 Itanium 的计算机的页面大小。
kd> ? 37d9bd3e*2000
Evaluate expression: 7676040298496 = 000006fb`37a7c000
然后,可以将范围的大小转换为字节:
kd> ? 37d9bd3e-37d9bd30+1 <-- computes the number of pages
Evaluate expression: 15 = 00000000`0000000f
kd> ? f*2000
Evaluate expression: 122880 = 00000000`0001e000
因此,ExplorerFrame.dll 从地址0x000006Fb'37A7C000 开始,0x1E000个字节大。 可以使用以下代码加载其符号:
kd> .reload /f ExplorerFrame.dll=6fb`37a7c000,1e000