第二章
🔬 第一阶段:保护模式基础(WinDbg实战)
现在就可以在你的调试环境中验证这些概念:
- 查看段寄存器现状
bash
bash
# 在WinDbg中(虚拟机中断状态下)
r gdtr # 查看GDTR寄存器(全局描述符表位置)
r ldtr # 查看LDTR寄存器(局部描述符表)
dg 0 0 # 显示GDT中的描述符(可能需要.shell命令)
0: kd> r gdtr
gdtr=fffff80487c9dfb0
0: kd> r ldtr
ldtr=0000
0: kd> dg 0 0
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0000 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
# 更实用的:查看当前段寄存器
r cs # 代码段
r ds # 数据段
r es # 附加段
r ss # 堆栈段
0: kd> r cs
cs=0010
0: kd> r ds
ds=002b
0: kd> r es
es=002b
0: kd> r ss
ss=0018
0: kd> r rax
rax=0000000000011201
0: kd> r rbx
rbx=ffffab012a405a90
- 查看描述符表内容
bash
bash
# 先获取GDTR地址
r gdtr
# 假设显示:gdtr=fffff80533a00fb0
# 查看GDT表内容(从基地址开始)
dq fffff805`33a00fb0 L20 # 查看前32个描述符(8字节一个)
0: kd> r gdtr
gdtr=fffff80487c9dfb0
0: kd> dq fffff80487c9dfb0 L20
fffff804`87c9dfb0 00000000`00000000 00000000`00000000 ; 四个字节,八位
fffff804`87c9dfc0 00209b00`00000000 00409300`00000000
fffff804`87c9dfd0 00cffb00`0000ffff 00cff300`0000ffff
fffff804`87c9dfe0 0020fb00`00000000 00000000`00000000
fffff804`87c9dff0 87008bc9`c0000067 00000000`fffff804
fffff804`87c9e000 0040f300`00003c00 00000000`00000000
fffff804`87c9e010 00000000`00000000 00000000`00000000
fffff804`87c9e020 00000000`00000000 00000000`00000000
fffff804`87c9e030 00000000`00000000 00000000`00000000
fffff804`87c9e040 00000000`00000000 00000000`00000000
fffff804`87c9e050 00000000`00000000 00000000`00000000
fffff804`87c9e060 00000000`00000000 00000000`00000000
fffff804`87c9e070 00000000`00000000 00000000`00000000
fffff804`87c9e080 00000000`00000000 00000000`00000000
fffff804`87c9e090 00000000`00000000 00000000`00000000
fffff804`87c9e0a0 00000000`00000000 00000000`00000000 ;16行 与L20有什么关系?
这个描述符的信息:
基地址:0x00000000 (平坦内存模型)
界限:0x00000000 (全0表示整个地址空间)
G位:0 (粒度字节)
D/B位:1 (32位段)
P位:1 (段存在)
DPL:11b = 3 (特权级3,用户模式)
Type:0011b (数据段,可读写,已访问)
实际意义
当内核代码需要访问用户空间数据时:
bash
将DS/ES寄存器设置为002Bh
这告诉CPU:"我要访问一个DPL=3的数据段"
CPU检查当前CPL(从CS的RPL获得)是否足够特权
因为内核CPL=0 ≥ DPL=3,允许访问
但用户代码无法反向访问内核数据
一个小小的改进建议
如果你想让标识更清晰,可以这样标记bit位置:
text
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
索引位(15-3)━━━━━━━━━━━━-━━━┓ ┃ ┃
索引=0101b TI=0 RPL=11
不过你现在的标识已经非常清晰和正确了!👍
总结:你的理解完全正确,分析得很透彻!这正是深入理解系统底层的方式。继续加油!💪
- 分析段选择子
bash
bash
# 查看CS段选择子
r cs
# 输出示例:cs=0010
# 手动解析0010h:
# 二进制:0000 0000 0001 0000
# 索引:0010b = 2(第3个描述符,索引从0开始)
# TI=0(使用GDT)
# RPL=00(特权级0,内核模式)
我来详细分析你提供的WinDbg输出数据:
- 段寄存器现状分析
从你的输出可以看到:
CS (代码段) = 0010h
DS (数据段) = 002Bh
ES (附加段) = 002Bh
SS (堆栈段) = 0018h
LDTR = 0000h (表示未使用局部描述符表)
- 解析段选择子 "段选择子=索引+TI+RPL"
bash
CS = 0010h (0000 0000 0001 0000b)
text
二进制:0000 0000 0001 0000
^^^ ^^^ ^^^ ^^^
| | | | \_ RPL = 00 (特权级0)
| | | \____ TI = 0 (使用GDT)
\___\___\_______ 索引 = 0010b = 2
索引:2 (第3个描述符,从0开始)
TI:0 (使用GDT)
RPL:00 (内核模式,特权级0)
DS = ES = 002Bh (0000 0000 0010 1011b)
text
二进制:0000 0000 0010 1011
^^^ ^^^ ^^^ ^^^
| | | | \_ RPL = 11 (特权级3)
| | | \____ TI = 0 (使用GDT)
\___\___\_______ 索引 = 0101b = 5
索引:5 (第6个描述符)
TI:0 (使用GDT)
RPL:11 (用户模式,特权级3)
为什么DS/ES在用户模式特权级?
这是Windows内核的标准设计:
CS=0010:内核代码段(RPL=00)
DS/ES=002B:用户模式数据段(RPL=11)
SS=0018:内核堆栈段(RPL=00)
当处理器在内核模式执行时:
CS使用特权级0的代码段
但可以访问特权级3的数据段(通过DS/ES)
这允许内核安全地访问用户空间数据
SS = 0018h (0000 0000 0001 1000b)
text
二进制:0000 0000 0001 1000
^^^ ^^^ ^^^ ^ ^^
| | | | \_ RPL = 00 (特权级0)
| | | \____ TI = 0 (使用GDT)
\___\___\_______ 索引 = 0011b = 3
索引:3 (第4个描述符)
TI:0 (使用GDT)
RPL:00 (内核模式,特权级0)
3. GDT内容分析
GDTR = fffff80487c9dfb0,查看前16个描述符(L20表示20个QWORD,即160字节,每8字节一个描述符):
text
地址 数据
fffff804`87c9dfb0 00000000`00000000 ; 索引0: 空描述符
fffff804`87c9dfc0 00209b00`00000000 ; 索引1
fffff804`87c9dfd0 00409300`00000000 ; 索引2 (CS=0010指向这个)
fffff804`87c9dfe0 00cffb00`0000ffff ; 索引3 (SS=0018指向这个)
fffff804`87c9dff0 00cff300`0000ffff ; 索引4
fffff804`87c9e000 0020fb00`00000000 ; 索引5 (DS/ES=002B指向这个)
解码CS段描述符 (索引2: 00409300`00000000)
text
低32位:00000000
高32位:00409300
格式:0040 9300 0000 0000
高Bit: 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 1
↑ ↑↑↑ ↑↑↑↑ ↑↑↑↑
| | |||
| | ||\_ P=1, DPL=00, S=1, Type=1011 (代码段,可读/执行)
| \____ G=0, D/B=1, L=0, AVL=0
\_________ 段基址[31:24]=00,段基址[23:16]=40
Access Byte (93h = 10010011b):
P = 1 (段存在)
DPL = 00 (特权级0)
S = 1 (代码/数据段)
Type = 0011b (表示可读/执行、已访问)
Flags (40h = 01000000b):
G = 0 (界限以字节为单位)
D/B = 1 (在32位代码段中表示"D"=1,表示32位操作数)
L = 0 (非64位代码段)
AVL = 0 (可供系统软件使用)
这是一个 32位代码段描述符,基址=0,界限=0,粒度=字节,是一个平坦模式的代码段。
✅ 核心内容提取(重点节选)
3.4 Segment Descriptors
段描述符是内存管理的基础数据结构,用于定义段的属性:
bash
段基址(32位或64位)
段界限(20位,可通过粒度位扩展)
访问权限(类型、特权级、存在性等)
系统标志(如粒度、默认大小、长模式位等)
字段详解
Limit (20位)
低16位在偏移 0--1
高4位在偏移 6 的低4位
粒度位 G 决定单位:G=0 表示字节,G=1 表示4KB页
Base (32位)
字节 2--4:Base 23:0
字节 7:Base 31:24
Access Byte (字节 5)
text
Bit 7: P (Present) - 1=段在内存中
Bits 6-5: DPL (Descriptor Privilege Level) - 00--11
Bit 4: S (Descriptor Type) - 1=代码/数据段,0=系统段
Bits 3-0: Type - 段类型编码
Flags (字节 6)
text
Bit 7: G (Granularity)
Bit 6: D/B (Default Operation Size)
- 代码段:D=1 表示32位代码,D=0 表示16位代码
- 数据段:B=1 表示32位栈,B=0 表示16位栈
Bit 5: L (Long Mode) - 1=64位代码段
Bit 4: AVL (Available for System Software)
Bits 3-0: Limit 19:16
3.4.5 Segment Descriptors in IA-32e Mode
在 64位模式(IA-32e) 下:
CS、DS、ES、SS 的基址被忽略(强制为0),实现平坦地址空间。
FS 和 GS 的基址仍然有效,可用于线性地址计算。
L 位(Long Mode)在代码段描述符中用于标识64位代码段。
D/B 位 在64位模式下被忽略(除CS外)。
段界限检查在64位模式下被禁用(除FS/GS外)。
3.7 Descriptor Tables
GDT (Global Descriptor Table)
包含系统所有任务可用的描述符。
bash
GDTR 寄存器指向 GDT。
LDT (Local Descriptor Table)
单个任务私有的描述符表。
LDTR 寄存器指向当前 LDT。
IDT (Interrupt Descriptor Table)
包含中断和异常处理程序的描述符。
4. 内存地址转换
在x86-64的长模式(Long Mode)下:
分段机制基本被禁用
大多数段基址都设置为0(除FS和GS段)
段界限通常为全0(表示整个64位地址空间)
你看到的这些主要是为了兼容性而保留
5. L20的含义解释
dq fffff80487c9dfb0 L20 命令:
dq = 显示QWORD(8字节)
L20 = 显示20个QWORD
20个QWORD × 8字节 = 160字节
每个描述符占8字节,所以显示20个描述符
你看到的输出是16行,因为每行显示2个QWORD(16字节)
这解释了为什么有16行输出:20个QWORD ÷ 每行2个 = 10行,加上地址前缀和空行,总共显示16行。
总结
你的系统运行在长模式(Long Mode)下,分段机制基本被禁用。段寄存器中的选择子主要用于:
CS:标识当前代码段和CPU特权级(00=内核模式)
DS/ES:标识当前数据段(RPL=11表示用户模式)
SS:标识当前堆栈段(特权级0)
在现代x64系统中,段基址通常为0,所有内存访问都使用平坦内存模型。
💻 第二阶段:分页机制实战(WinDbg核心)
这才是Windows内核调试的精华所在:
bash
1. 查看当前分页模式
bash
# 查看控制寄存器
r cr0 # 包含PE(保护模式使能)和PG(分页使能)位
r cr4 # 包含PAE(物理地址扩展)等位
0: kd> r cs
cs=0010
0: kd> !gdt 2 2
gdt is not extension gallery command
No export gdt found
0: kd> dg cs cs
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0010 00000000`00000000 00000000`00000000 Code RE Ac 0 Nb By P Lo 0000029b
0: kd> rdmsr 0xC0000080
msr[c0000080] = 00000000`00000d01
0: kd> r cr0
cr0=0000000080050033
0: kd> r cr4
cr4=0000000000370678
# 关键判断:
# CR0.PE = 1 表示保护模式已开启
# CR0.PG = 1 表示分页已开启
# CR4.PAE = 1 表示使用PAE分页(2-9-9-12分页)
2. 查看CR3(页目录基址)
bash
r cr3
0: kd> r cr3
cr3=00000000001ad002
# 输出示例:cr3=00000000001ad002
# 这是物理地址!WinDbg会自动转换
!pte fffff805`33400000 # 分析指定线性地址的页表转换
0: kd> !pte fffff805`33400000
VA fffff80533400000
PXE at FFFFF57ABD5EAF80 PPE at FFFFF57ABD5F00A0 PDE at FFFFF57ABE014CD0 PTE at FFFFF57C0299A000
contains 0000000004C09063 contains 0A000000BCA39863 contains 0A0000000243D863 contains 00007A3400000010
pfn 4c09 ---DA--KWEV pfn bca39 ---DA--KWEV pfn 243d ---DA--KWEV not valid
Page has been freed
3. 手动追踪地址转换
让我们追踪一个内核地址,比如 nt!MiInitializePfn:
bash
# 1. 获取符号地址
x nt!MiInitializePfn
0: kd> x nt!MiInitializePfn
fffff804`84cc4130 nt!MiInitializePfn (MiInitializePfn)
# 2. 分析该地址的页表转换
!pte fffff804`84cc4130
0: kd> !pte fffff804`84cc4130
VA fffff80484cc4130
PXE at FFFFF57ABD5EAF80 PPE at FFFFF57ABD5F0090 PDE at FFFFF57ABE012130 PTE at FFFFF57C02426620
contains 0000000004C09063 contains 0000000004C10063 contains 0A00000002E000A1 contains 0000000000000000
pfn 4c09 ---DA--KWEV pfn 4c10 ---DA--KWEV pfn 2e00 --L-A--KREV LARGE PAGE pfn 2ec4
# 3. 输出会显示类似:
# VA fffff805336a1234
# PDE at FFFFF6FB7DBED80 contains 0000000001A90067
# PTE at FFFFF6FB7D9B5090 contains 8000000001A92025
# 得到物理地址 1A91234
====================================
展示了 x86-64(Intel 64)架构下 Windows 内核的分页结构,并且使用的是 PAE(Physical Address Extension)模式下的 4-level 分页(即 9-9-9-12 分页)。我们来逐项分析,并解释关键点。
🔍 一、控制寄存器状态分析
bash
✅ CR0 = 0x80050033
转换为二进制(只看关键位):
text
编辑
CR0 = 1000 0000 0000 0101 0000 0000 0011 0011
^ ^ ^
PE MP PG
• CR0.PE (bit 0) = 1 → 保护模式已启用
• CR0.PG (bit 31) = 1 → 分页机制已启用
✅ 系统运行在 启用分页的保护模式 下 ------ 这是现代操作系统的基本前提。
________________________________________
✅ CR4 = 0x00370678
重点关注:
• CR4.PAE (bit 5) = 1 → 启用 PAE(物理地址扩展)
• CR4.LA57 (bit 12) = 0 → 未启用 5-level 分页(即不是 Intel 的 57-bit 地址)
• 其他如 SMEP、SMAP 等也可能开启(bit 20/21),但此处不展开
✅ 所以当前使用的是 4-level 分页(PML4 → PDPT → PD → PT),每级 9 位,页内偏移 12 位,共 48 位虚拟地址(canonical form)。
注:Windows x64 在启用 PAE 后默认使用 4-level 分页,即使物理内存 < 4GB。
🔍 二、CR3 寄存器:页目录基址
bash
bash
编辑
cr3 = 0x00000000001ad002
• CR3 存储的是 PML4 表(Page Map Level 4 Table)的物理基地址
• 最低 12 位是控制位(如 PCD、PWT、PCID 等)
• 此处 0x002 表示:
• bit 0: Present = 1(有效)
• bit 1: Reserved = 0(必须为 0)
• bit 2--11: 可能包含 PCID(Process Context ID)等(但通常为 0)
所以 PML4 表物理地址 = 0x1AD000(对齐到 4KB)
🔍 三、!pte 分析:虚拟地址 → 物理页映射
bash
示例 1:fffff80533400000`
输出:
text
编辑
VA fffff80533400000
PXE at FFFFF57ABD5EAF80 → PML4E
PPE at FFFFF57ABD5F00A0 → PDPT Entry
PDE at FFFFF57ABE014CD0 → Page Directory Entry
PTE at FFFFF57C0299A000 → Page Table Entry
...
contains ... not valid
Page has been freed
• 所有页表项(PML4E, PDPT, PDE)都有效(含 PFN 和标志)
• 但 PTE 无效(not valid),且提示 "Page has been freed"
• 说明该虚拟地址曾被映射,但现在对应的物理页已被释放(可能是池内存或动态分配区域)
💡 fffff80000000000 ~ fffff87fffffffff 是 Windows 内核非换页池、驱动代码等区域。此地址可能属于某个已卸载模块或释放的缓冲区。
________________________________________
示例 2:nt!MiInitializePfn → fffff80484cc4130`
bash
编辑
VA fffff80484cc4130
PXE ... contains 0000000004C09063 → pfn 4c09
PPE ... contains 0000000004C10063 → pfn 4c10
PDE ... contains 0A00000002E000A1 → LARGE PAGE
关键点:
• PDE 标志为 LARGE PAGE(即 bit 7 = PS = 1)
• 表示这是一个 2MB 大页(Huge Page),跳过了 PTE 层
• PFN = 0x2EC4 → 物理页帧号
• 物理地址 = 0x2EC4 << 21 + 页内偏移(低 21 位)
计算:
• 虚拟地址:fffff80484cc4130`
• 页内偏移(21 位)= 0x4cc4130 & 0x1FFFFF = 0xcc4130
• 物理地址 = (0x2EC4 << 21) + 0xcc4130 = 0x5D8800000 + 0xcc4130 = 0x5D94C4130
✅ 这说明 MiInitializePfn 函数代码位于一个 2MB 大页映射的内核代码段中 ------ 这是 Windows 内核优化的一部分(减少 TLB 压力)。
🧠 总结:当前系统分页状态
项目 状态
架构 x86-64(Intel 64)
分页模式 4-level(PML4 → PDPT → PD → PT)
页大小 支持 4KB 和 2MB(大页)
CR0.PE 1(保护模式)
CR0.PG 1(分页启用)
CR4.PAE 1(启用 PAE)
CR4.LA57 0(未启用 5-level 分页)
内核地址空间 使用 canonical 地址(高地址 fffff8xx...)
页表基址 CR3 = 0x1AD000
🔧 建议调试命令(继续深入)
bash
你可以进一步探索:
bash
编辑
# 查看 PML4 表内容(物理地址转虚拟)
!dq poi(@cr3) L20 # 显示前 0x100 字节(32 个 PML4E)
0: kd> !dq poi(@cr3) L20
# 0 00000000`00000000 00000000`00000000
# 10 00000000`00000000 00000000`00000000
# 20 00000000`00000000 00000000`00000000
# 30 00000000`00000000 00000000`00000000
# 40 00000000`c0000007 00000000`00000000
# 50 00000000`00000000 00000000`00000000
# 60 00000000`00000000 00000000`00000000
# 70 00000000`00000000 00000000`00000000
# 查看某个 PFN 对应的物理页内容
!db 0x2EC4000 L100 # 注意:需用 !db / !dd,且地址是物理地址(需启用物理内存访问)
0: kd> !db 0x2EC4000 L100
# 2ec4000 00 00 45 8b c8 48 8b d6-44 8b c3 49 8b ca e8 1d ..E..H..D..I....
# 2ec4010 01 00 00 0f ba eb 1d 49-8b d7 44 8b c3 48 8b ce .......I..D..H..
# 2ec4020 e8 3b ce fb ff 48 8b ce-48 8b d8 e8 90 f3 f7 ff .;...H..H.......
# 2ec4030 85 c0 0f 85 13 28 19 00-48 89 1e 8b 07 a8 04 0f .....(..H.......
# 2ec4040 85 79 28 19 00 44 8b 84-24 a0 00 00 00 41 ff c6 .y(..D..$....A..
# 2ec4050 41 8b c6 48 81 c5 00 10-00 00 48 83 c6 08 48 b9 A..H......H...H.
# 2ec4060 00 00 00 00 80 82 ff ff-49 bf ff ff ff ff 0f 00 ........I.......
# 2ec4070 00 00 48 ba ab aa aa aa-aa aa aa 2a 49 3b 04 24 ..H........*I;.$
# 2ec4080 0f 82 f7 fe ff ff b8 11-01 00 00 48 8b 9c 24 98 ...........H..$.
# 2ec4090 00 00 00 48 83 c4 50 41-5f 41 5e 41 5d 41 5c 5f ...H..PA_A^A]A\_
# 2ec40a0 5e 5d c3 cc 41 83 c8 20-44 89 84 24 a0 00 00 00 ^]..A.. D..$....
# 2ec40b0 e9 4d ff ff ff 4c 8d 2c-40 49 c1 e5 04 48 8b c1 .M...L.,@I...H..
# 2ec40c0 4c 03 e8 e9 d3 fe ff ff-41 8b 46 30 0f ba e0 14 L.......A.F0....
# 2ec40d0 0f 82 0f fe ff ff 48 c1-e8 12 48 8d 0d bf 9d d6 ......H...H.....
# 2ec40e0 ff 83 e0 03 48 83 3c c1-10 0f 85 f6 fd ff ff e9 ....H.<.........
# 2ec40f0 5c 26 19 00 41 8b 46 34-41 0f b6 4e 22 0f ba f0 \&..A.F4A..N"...
# 检查是否启用了 SMEP/SMAP
r cr4
# bit 20 = SMEP, bit 21 = SMAP
0: kd> r cr4
cr4=0000000000370678
# 查看所有大页映射
!vm 4 # 显示大页使用情况
0: kd> !vm 4
unable to get nt!PspSessionIdBitmap
Page File: \??\C:\pagefile.sys
Current: 1441792 Kb Free Space: 1441784 Kb
Minimum: 1441792 Kb Maximum: 7771256 Kb
Page File: \??\C:\swapfile.sys
Current: 16384 Kb Free Space: 16376 Kb
Minimum: 16384 Kb Maximum: 6217004 Kb
Virtual Store Paging File
Current: 11964052 Kb Free Space: 11893144 Kb
Minimum: 11964052 Kb Maximum: 11964052 Kb
Physical Memory: 1048199 ( 4192796 Kb)
Available Pages: 509143 ( 2036572 Kb)
ResAvail Pages: 863593 ( 3454372 Kb)
Locked IO Pages: 0 ( 0 Kb)
Free System PTEs: 4294987703 (17179950812 Kb)
******* 294720 kernel stack PTE allocations have failed ******
******* 2237983104 kernel stack growth attempts have failed ******
Modified Pages: 12805 ( 51220 Kb)
Modified PF Pages: 12232 ( 48928 Kb)
Modified No Write Pages: 0 ( 0 Kb)
NonPagedPool Usage: 233 ( 932 Kb)
NonPagedPoolNx Usage: 36097 ( 144388 Kb)
NonPagedPool Max: 4294967296 (17179869184 Kb)
PagedPool Usage: 33156 ( 132624 Kb)
PagedPool Maximum: 4294967296 (17179869184 Kb)
Processor Commit: 442 ( 1768 Kb)
Unable to read nt!_LIST_ENTRY.Flink at 0000000000000000
Shared Commit: 23083 ( 92332 Kb)
Kernel Stacks: 7830 ( 31320 Kb)
Pages For MDLs: 4463 ( 17852 Kb)
ContigMem Pages: 0 ( 0 Kb)
Partition Pages: 0 ( 0 Kb)
Pages For AWE: 0 ( 0 Kb)
NonPagedPool Commit: 37081 ( 148324 Kb)
PagedPool Commit: 33156 ( 132624 Kb)
Driver Commit: 12527 ( 50108 Kb)
Boot Commit: 4721 ( 18884 Kb)
PFN Array Commit: 12832 ( 51328 Kb)
SmallNonPagedPtesCommit: 132 ( 528 Kb)
SlabAllocatorPages: 4608 ( 18432 Kb)
SkPagesInUnchargedSlabs: 0 ( 0 Kb)
CrossPartitionCommit: 0 ( 0 Kb)
System PageTables: 2242 ( 8968 Kb)
ProcessLockedFilePages: 12 ( 48 Kb)
Pagefile Hash Pages: 0 ( 0 Kb)
Sum System Commit: 143129 ( 572516 Kb)
Total Private: 350919 ( 1403676 Kb)
Misc/Transient Commit: 623 ( 2492 Kb)
Committed pages: 494671 ( 1978684 Kb)
Commit limit: 1408647 ( 5634588 Kb)
Pid ImageName Commit SharedCommit Debt
b68 SkypeApp.exe 196644 Kb 2828 Kb 0 Kb
c38 MsMpEng.exe 140848 Kb 2432 Kb 0 Kb
1848 SearchApp.exe 114296 Kb 15304 Kb 0 Kb
71c CompatTelRunner.exe 69020 Kb 2372 Kb 0 Kb
fdc MSPCManagerService.exe 68972 Kb 2676 Kb 0 Kb
1374 explorer.exe 60508 Kb 13512 Kb 0 Kb
3f8 dwm.exe 55720 Kb 18336 Kb 0 Kb
1f58 msedge.exe 52332 Kb 9320 Kb 0 Kb
1068 SkypeBridge.exe 34164 Kb 3604 Kb 0 Kb
17ec svchost.exe 28192 Kb 3332 Kb 0 Kb
1f30 vmtoolsd.exe 24236 Kb 3724 Kb 0 Kb
13a4 WmiPrvSE.exe 22984 Kb 2192 Kb 0 Kb
204 StartMenuExperienceHost. 22804 Kb 2996 Kb 0 Kb
1f80 OneDrive.exe 19472 Kb 4784 Kb 0 Kb
bbc svchost.exe 18992 Kb 2368 Kb 0 Kb
55c svchost.exe 17652 Kb 2016 Kb 0 Kb
fe4 SearchIndexer.exe 17284 Kb 2888 Kb 0 Kb
21c TextInputHost.exe 15628 Kb 5700 Kb 0 Kb
c28 WmiPrvSE.exe 12496 Kb 2288 Kb 0 Kb
bd8 svchost.exe 11852 Kb 2056 Kb 0 Kb
1c58 msedge.exe 11816 Kb 3304 Kb 0 Kb
3f4 RuntimeBroker.exe 11352 Kb 2596 Kb 0 Kb
1c08 msedge.exe 11092 Kb 3564 Kb 0 Kb
bc8 svchost.exe 10528 Kb 2156 Kb 0 Kb
314 svchost.exe 9796 Kb 2436 Kb 0 Kb
13d8 ctfmon.exe 9632 Kb 4992 Kb 0 Kb
a4c svchost.exe 8976 Kb 2020 Kb 0 Kb
1228 svchost.exe 8968 Kb 2552 Kb 0 Kb
1eac msedge.exe 8544 Kb 1644 Kb 0 Kb
191c RuntimeBroker.exe 7788 Kb 3504 Kb 0 Kb
294 lsass.exe 7416 Kb 2408 Kb 0 Kb
380 svchost.exe 7136 Kb 444 Kb 0 Kb
8ec svchost.exe 7076 Kb 2052 Kb 0 Kb
fec svchost.exe 7004 Kb 2052 Kb 0 Kb
7b4 conhost.exe 6680 Kb 4000 Kb 0 Kb
c48 vmtoolsd.exe 6316 Kb 2092 Kb 0 Kb
28c services.exe 6228 Kb 440 Kb 0 Kb
1278 taskhostw.exe 6168 Kb 3660 Kb 0 Kb
568 svchost.exe 6004 Kb 2052 Kb 0 Kb
11bc sihost.exe 5980 Kb 2540 Kb 0 Kb
1e48 RuntimeBroker.exe 5828 Kb 2560 Kb 0 Kb
11c8 svchost.exe 5724 Kb 2552 Kb 0 Kb
1138 NisSrv.exe 5288 Kb 2016 Kb 0 Kb
490 svchost.exe 5280 Kb 2312 Kb 0 Kb
a18 spoolsv.exe 5236 Kb 2052 Kb 0 Kb
5e8 svchost.exe 4736 Kb 2016 Kb 0 Kb
1678 svchost.exe 4624 Kb 2056 Kb 0 Kb
c50 svchost.exe 4576 Kb 2336 Kb 0 Kb
994 ChsIME.exe 4416 Kb 2348 Kb 0 Kb
1a20 svchost.exe 4392 Kb 2024 Kb 0 Kb
18a8 svchost.exe 4148 Kb 2020 Kb 0 Kb
aac svchost.exe 4068 Kb 2064 Kb 0 Kb
bb4 svchost.exe 4056 Kb 2152 Kb 0 Kb
5c Registry 4020 Kb 0 Kb 0 Kb
ef4 dllhost.exe 4012 Kb 2048 Kb 0 Kb
8f8 SgrmBroker.exe 3960 Kb 416 Kb 0 Kb
f08 svchost.exe 3952 Kb 2052 Kb 0 Kb
738 svchost.exe 3852 Kb 2032 Kb 0 Kb
15a4 svchost.exe 3812 Kb 2548 Kb 0 Kb
129c svchost.exe 3780 Kb 2336 Kb 0 Kb
f90 dllhost.exe 3336 Kb 2388 Kb 0 Kb
5a4 svchost.exe 3256 Kb 2352 Kb 0 Kb
1ef0 SecurityHealthService.ex 3212 Kb 2064 Kb 0 Kb
4c4 svchost.exe 3056 Kb 2544 Kb 0 Kb
230 msdtc.exe 3056 Kb 2024 Kb 0 Kb
888 svchost.exe 3052 Kb 2024 Kb 0 Kb
74c svchost.exe 3024 Kb 2020 Kb 0 Kb
1c40 svchost.exe 2940 Kb 2020 Kb 0 Kb
c18 VGAuthService.exe 2916 Kb 2064 Kb 0 Kb
75c svchost.exe 2900 Kb 2056 Kb 0 Kb
b14 svchost.exe 2884 Kb 2344 Kb 0 Kb
730 svchost.exe 2864 Kb 2020 Kb 0 Kb
c10 svchost.exe 2812 Kb 2052 Kb 0 Kb
1530 RuntimeBroker.exe 2744 Kb 2364 Kb 0 Kb
12a8 MicrosoftEdgeUpdate.exe 2728 Kb 2064 Kb 0 Kb
1ad4 svchost.exe 2656 Kb 2340 Kb 0 Kb
8e0 svchost.exe 2648 Kb 2016 Kb 0 Kb
1e9c svchost.exe 2600 Kb 2056 Kb 0 Kb
628 svchost.exe 2568 Kb 2336 Kb 0 Kb
145c svchost.exe 2560 Kb 2052 Kb 0 Kb
248 winlogon.exe 2496 Kb 5276 Kb 0 Kb
3ac svchost.exe 2392 Kb 2052 Kb 0 Kb
9f8 svchost.exe 2380 Kb 2052 Kb 0 Kb
d98 svchost.exe 2376 Kb 2304 Kb 0 Kb
4a8 svchost.exe 2348 Kb 2028 Kb 0 Kb
98c svchost.exe 2332 Kb 2052 Kb 0 Kb
200 csrss.exe 2320 Kb 8252 Kb 0 Kb
450 svchost.exe 2288 Kb 2024 Kb 0 Kb
908 svchost.exe 2276 Kb 2020 Kb 0 Kb
494 svchost.exe 2256 Kb 2056 Kb 0 Kb
668 svchost.exe 2096 Kb 2016 Kb 0 Kb
1f8c msedge.exe 2076 Kb 3188 Kb 0 Kb
af0 svchost.exe 2060 Kb 2020 Kb 0 Kb
11d0 SkypeBackgroundHost.exe 2020 Kb 2604 Kb 0 Kb
308 fontdrvhost.exe 2012 Kb 424 Kb 0 Kb
a84 svchost.exe 2000 Kb 2020 Kb 0 Kb
b84 svchost.exe 1996 Kb 2020 Kb 0 Kb
468 svchost.exe 1988 Kb 2024 Kb 0 Kb
7fc svchost.exe 1872 Kb 2056 Kb 0 Kb
2b0 svchost.exe 1872 Kb 2060 Kb 0 Kb
438 svchost.exe 1864 Kb 2020 Kb 0 Kb
1510 svchost.exe 1856 Kb 2016 Kb 0 Kb
724 svchost.exe 1848 Kb 2080 Kb 0 Kb
1ac csrss.exe 1820 Kb 8288 Kb 0 Kb
ff8 svchost.exe 1816 Kb 2052 Kb 0 Kb
1388 svchost.exe 1808 Kb 2052 Kb 0 Kb
92c svchost.exe 1800 Kb 2020 Kb 0 Kb
1ec8 SecurityHealthSystray.ex 1764 Kb 2264 Kb 0 Kb
3e0 svchost.exe 1748 Kb 2052 Kb 0 Kb
b5c svchost.exe 1696 Kb 2048 Kb 0 Kb
1e68 taskhostw.exe 1652 Kb 3188 Kb 0 Kb
f84 svchost.exe 1644 Kb 2056 Kb 0 Kb
d40 vm3dservice.exe 1552 Kb 3204 Kb 0 Kb
300 fontdrvhost.exe 1528 Kb 424 Kb 0 Kb
1e54 svchost.exe 1508 Kb 2052 Kb 0 Kb
8fc svchost.exe 1500 Kb 2016 Kb 0 Kb
1f8 wininit.exe 1476 Kb 1996 Kb 0 Kb
c20 vm3dservice.exe 1456 Kb 2048 Kb 0 Kb
8d8 ChsIME.exe 1444 Kb 2260 Kb 0 Kb
440 svchost.exe 1408 Kb 2020 Kb 0 Kb
3e8 svchost.exe 1400 Kb 2016 Kb 0 Kb
5dc svchost.exe 1392 Kb 2020 Kb 0 Kb
770 svchost.exe 1312 Kb 2048 Kb 0 Kb
c94 svchost.exe 1284 Kb 2024 Kb 0 Kb
42c svchost.exe 1252 Kb 2016 Kb 0 Kb
c04 svchost.exe 1248 Kb 2048 Kb 0 Kb
1f7c CompatTelRunner.exe 1204 Kb 2048 Kb 0 Kb
134 smss.exe 1068 Kb 328 Kb 0 Kb
4 System 196 Kb 292 Kb 0 Kb 7c8 MemCompression 144 Kb 0 Kb 0 Kb
e74 msedge.exe 132 Kb 0 Kb 0 Kb
44c svchost.exe 80 Kb 0 Kb 0 Kb
19c0 svchost.exe 76 Kb 0 Kb 0 Kb
bec userinit.exe 76 Kb 0 Kb 0 Kb
Terminal Server Memory Usage By Session:
Unable to read nt!_LIST_ENTRY.Flink at 0000000000000000
系统性地分析这些信息,重点关注 分页结构、SMEP/SMAP 状态、大页使用情况,以及一些潜在的异常点。
✅ 一、确认 SMEP / SMAP 是否启用
bash
你执行了:
bash
编辑
r cr4
cr4=0000000000370678
将 0x370678 转为二进制(关注 bit 20 和 bit 21):
text
编辑
0x370678 = 0011 0111 0000 0110 0111 1000
^ ^
bit 21 bit 20
• bit 20 (SMEP) = 1 → ✅ Supervisor Mode Execution Prevention 已启用
• bit 21 (SMAP) = 1 → ✅ Supervisor Mode Access Prevention 已启用
🔒 这意味着:
• 内核代码 不能直接执行用户空间内存(SMEP)
• 内核代码 不能直接读写用户空间内存(除非用 STAC/CLAC 指令临时关闭 SMAP)
这是现代 Windows 的标准安全防护机制。
✅ 二、PML4 表内容分析
bash
你执行:
bash
编辑
!dq poi(@cr3) L20
输出关键行:
text
编辑
# 40 00000000`c0000007 00000000`00000000
即 PML4[0x10] = 0xc0000007(因为偏移 0x40 ÷ 8 = 8,但注意:x64 使用高地址 canonical 形式,实际索引由 VA 高位决定)
但更重要的是:
• 大部分 PML4E 为 0 → 未映射
• 只有少数项非零,比如 0xc0000007
拆解 0xc0000007:
• PFN = 0xc0000(高 28 位右移 12 位 → 0xc0000000 >> 12 = 0xc0000)
• 标志:0x7 = P | RW | US(Present, Read/Write, User)
• 但内核地址通常不设 US(User),这里可能是调试器显示问题或特殊区域(如 shared user data)
📌 注意:Windows 内核地址空间通常从 fffff80000000000 开始,对应 PML4 索引 0x100 ~ 0x1ff(因为 fffff800... 的高 16 位是 0xFFFFF8,canonical 扩展后 PML4 index = (VA >> 39) & 0x1FF)
但你的 !dq poi(@cr3) 只显示了低地址项(0~0x1F),所以 看不到内核高地址的 PML4E。要查看内核 PML4 项,应计算索引:
例如:VA = fffff80484cc4130`
• PML4 index = (0xfffff80484cc4130 >> 39) & 0x1FF = 0x100 + 4 = 0x104
• 所以 PML4E 在 CR3 + 0x104 * 8 = CR3 + 0x820
你可以用:
bash
编辑
!dq poi(@cr3) + 0x820 L1
来查看该项。
✅ 三、物理页内容分析(MiInitializePfn 所在大页)
bash
你执行:
bash
编辑
!db 0x2EC4000 L100
输出开头:
text
编辑
2ec4000 00 00 45 8b c8 48 8b d6 ...
反汇编片段(x64):
asm
编辑
45 8B C8 mov r9d, r8d
48 8B D6 mov rdx, rsi
...
✅ 这确实是 合法的 x64 内核代码,属于 ntoskrnl.exe 的一部分(MiInitializePfn 是内存管理函数)。
而且你之前看到:
text
编辑
LARGE PAGE pfn 2ec4
说明 Windows 将内核关键代码段映射为 2MB 大页,这是正常行为,用于提升 TLB 效率。
⚠️ 四、!vm 4 输出中的异常信息
bash
虽然 !vm 4 主要显示内存使用统计,但有两行 严重警告:
text
编辑
******* 294720 kernel stack PTE allocations have failed ******
******* 2237983104 kernel stack growth attempts have failed ******
含义:
• 内核栈分配失败次数极高(近 30 万次 PTE 分配失败,超 22 亿次增长失败)
• 这通常表明:
• NonPagedPool 耗尽(但你的 NonPagedPool Usage 仅 145MB,远低于 Max)
• System PTE 耗尽(但 Free System PTEs 显示为 4294987703 ≈ -20000,这很可疑!)
关键线索:
text
编辑
Free System PTEs: 4294987703 (17179950812 Kb)
• 4294987703 是一个 接近 2^32 的数,实际应为 负数(因为 System PTE 总数约几万到几十万)
• 这极可能是 整数溢出或符号错误,真实值可能 非常小甚至为负
💥 结论:System PTE 资源已严重不足!
后果:
• 内核无法分配新栈(每个线程需要 ~24KB 内核栈)
• 驱动加载、APC、DPC 等可能失败
• 系统可能蓝屏(如 KERNEL_STACK_INPAGE_ERROR, SYSTEM_PTE_MISUSE)
建议:
• 检查是否有 驱动泄漏 PTE(尤其是显卡、杀毒软件、虚拟化工具)
• 使用:
bash
编辑
!sysptes
查看 System PTE 详细使用情况
• 升级到最新 Windows 版本(某些旧版本存在 PTE 泄漏 bug)
• 减少并发线程数(如限制服务、关闭不必要的后台程序)
✅ 五、其他观察
• 物理内存:约 4GB(1048199 pages × 4KB ≈ 4.19GB)
• 可用内存充足(Available Pages ≈ 2GB)
• 页面文件配置合理
• 无 AWE、Contiguous Memory 使用
所以问题 不是物理内存不足,而是虚拟内存管理资源(System PTE)耗尽。