Windows x64内核

9-9-9-9-12分页机制介绍

之前我们学过的x86用的是2-9-9-12和10-10-12的分页机制

x64下,分页大小有4K,2M,1G的大小

如果PDE的PS位为0,则为4K,为1则为2M

如果PDPTE 的PS=1的话,指向 1GB 页

x64下,4k分页变成了9-9-9-9-12的分页机制

虽然64位下的地址有64位,但是实际用到的只有48位,这主要因为以下原因:

  1. 当前需求有限

  2. 管理复杂度

  • 使用完整的 64 位地址空间将引入极大的管理和硬件复杂性。
  1. 页表大小和效率
  • 使用四级页表(9-9-9-9-12 分级结构)能够有效管理 48 位的虚拟地址空间。使用更多位数意味着增加页表层级,可能需要五级或更多级页表,这会带来额外的内存和性能开销。当前四级页表架构已经能够高效地处理 48 位地址,而无需增加复杂性。

1725351574352

我们来依次解析下每一个数字的含义:

PML4(Page Map Level 4):页目录指针表

在windows叫PXE

  • 最高的页表层级,用 9 位来索引 PML4 表项。PML4 表最多可以有 512 个条目。每个 PML4 表项指向一个 PDPT 表。
    1725351737296
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct PML4Entry {
uint64_t present : 1; // P - 1表示有效,0表示无效。
uint64_t writable : 1; // R/W - 可写位,0表示只读,1表示可读写。
uint64_t userAccessible : 1; // U/S - 控制访问权限。0表示内核模式,1表示用户模式。
uint64_t writeThrough : 1; // PWT - 写通位
uint64_t cacheDisable : 1; // PCD - 缓存禁用位
uint64_t accessed : 1; // A - 访问位
uint64_t ignored1 : 1; // IGN - 忽略位 (1 bit)
uint64_t mustBeZero1 : 1; // MBZ - 保留位,必须为 0,其实就是PS位
uint64_t mustBeZero2 : 1; // MBZ - 保留位,必须为 0
uint64_t available : 3; // AVL - 操作系统可用位(3 bit)
uint64_t pml3Address : 40; // 页目录基地址
uint64_t availableHigh : 11; // 操作系统可用位高位
uint64_t noExecute : 1; // NX - 禁止执行位,1是不可执行,0是可执行
};

PDPTE(Page Directory Pointer Table Entry):页目录指针表项

在windows叫PPE

  • 第二级页表层级,也用 9 位来索引。每个 PDPT 表最多包含 512 个条目。每个 PDPTE 指向一个页目录表(PDE)。
    1725352425534

PDE(Page Directory Entry):页目录表项

  • 第三级页表层级,继续用 9 位来索引。PDE 表最多包含 512 个条目。每个 PDE 指向一个页表(PTE)。

PTE(Page Table Entry):页表项

  • 第四级页表层级,仍然用 9 位来索引。PTE 表最多包含 512 个条目。每个 PTE 指向一个实际的物理页帧。

Page Offset(页内偏移)

  • 最后的 12 位用于页内偏移,表示一个 4KB 页内的具体地址。

TLB(Translation Lookaside Buffer) 是一种用于提高虚拟地址到物理地址转换效率的高速缓存。它是一种专用的硬件缓存,存储了最近使用的页表条目,以加速内存访问。

以下是刷新TLB的代码(不是无效代码)

1
2
mov eax,cr3
mov cr3,eax

实战找4K页的物理地址

例如我们现在分析这个虚拟地址的物理地址

1725361499101

用.formats分析一波

1
2
3
4
5
6
7
8
9
10
11
1: kd> .formats fffff800`03ca3420
Evaluate expression:
Hex: fffff800`03ca3420
Decimal: -8796029438944
Decimal (unsigned) : 18446735277680112672
Octal: 1777777600000362432040
Binary: 11111111 11111111 11111000 00000000 00000011 11001010 00110100 00100000
Chars: ......4
Time: ***** Invalid FILETIME
Float: low 1.18845e-036 high -1.#QNAN
Double: -1.#QNAN

拆开分析

1
2
3
4
5
6
7
1 1111 0000   0x1F0	
0 0000 0000 0x0
0 0001 1110 0x1E
0 1010 0011 0xA3


0100 0010 0000 0x420

下面是Windbg查询的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
1: kd> r cr3
cr3=0000000000187000

1: kd> !dq 0000000000187000+ 0x1F0*0x8
# 187f80 00000000`00199063 00000000`78f04863
# 187f90 00000000`00000000 00000000`2fe42863
# 187fa0 00000000`00000000 00000000`05400863
# 187fb0 00000000`00000000 00000000`00000000
# 187fc0 00000000`00000000 00000000`00000000
# 187fd0 00000000`00000000 00000000`00000000
# 187fe0 00000000`00000000 00000000`00000000
# 187ff0 00000000`00000000 00000000`001f3063

1: kd> !dq 00000`00199000+ 0x0 *8
# 199000 00000000`00198063 00000000`00000000
# 199010 00000000`00000000 00000000`00000000
# 199020 00000000`00000000 00000000`00000000
# 199030 00000000`00000000 00000000`00000000
# 199040 00000000`00000000 00000000`00000000
# 199050 00000000`00000000 00000000`00000000
# 199060 00000000`00000000 00000000`00000000
# 199070 00000000`00000000 00000000`00000000

1: kd> !dq 00000`00198000+0x1e*8
# 1980f0 00000000`001e2063 00000000`001e3063
# 198100 00000000`001e4063 00000000`001e5063
# 198110 00000000`00000000 00000000`00000000
# 198120 00000000`00000000 00000000`00000000
# 198130 00000000`00000000 00000000`00000000
# 198140 00000000`001ec063 00000000`00000000
# 198150 00000000`00000000 00000000`00000000
# 198160 00000000`00000000 00000000`00000000

1: kd> !dq 00000`001e2000+0xA3*8
# 1e2518 00000000`03ca3021 00000000`03ca4021
# 1e2528 00000000`03ca5021 00000000`03ca6021
# 1e2538 00000000`03ca7021 00000000`03ca8021
# 1e2548 00000000`03ca9021 00000000`03caa021
# 1e2558 00000000`03cab021 00000000`03cac021
# 1e2568 00000000`03cad021 00000000`03cae021
# 1e2578 00000000`03caf021 00000000`03cb0021
# 1e2588 00000000`03cb1021 00000000`03cb2021

1: kd> !dq 00000`03ca3000+0x420
# 3ca3420 cccccccc`ccccc3cc 00000000`00841f0f
# 3ca3430 8b66c28b`44c88b45 0001b808`498b4811
# 3ca3440 ccccc3cc`2dcd0000 00401f0f`cccccccc
# 3ca3450 428b4c02`4a8b4466 08498b48`118b6608
# 3ca3460 cc2dcd00`000002b8 90cccccc`ccccccc3
# 3ca3470 ccc3cc2d`cdc08b41 cccccccc`cccccccc
# 3ca3480 6666cccc`cccccccc 00000000`00841f0f
# 3ca3490 8408418b`48118b48 8b48c3c8`fe0374c0

查看虚拟地址,发现也是正确的

1
2
3
4
5
6
7
8
9
1: kd> dq fffff800`03ca3420
fffff800`03ca3420 cccccccc`ccccc3cc 00000000`00841f0f
fffff800`03ca3430 8b66c28b`44c88b45 0001b808`498b4811
fffff800`03ca3440 ccccc3cc`2dcd0000 00401f0f`cccccccc
fffff800`03ca3450 428b4c02`4a8b4466 08498b48`118b6608
fffff800`03ca3460 cc2dcd00`000002b8 90cccccc`ccccccc3
fffff800`03ca3470 ccc3cc2d`cdc08b41 cccccccc`cccccccc
fffff800`03ca3480 6666cccc`cccccccc 00000000`00841f0f
fffff800`03ca3490 8408418b`48118b48 8b48c3c8`fe0374c0

分页大小为2M的情况

2M的情况就没有了PTE(Page Table Entry):页表项,且最后的偏移变成了20位

1725362953268

其他和分页大小是4K的并无啥区别

另外1G的页,机制为9-9-30

x64新加的保护机制

SMEP

Supervisor Mode Execution Prevention (SMEP) 是一种硬件级别的安全机制,旨在防止操作系统内核(即特权级 0)执行用户模式(即特权级 3)内存中的代码。这是通过在处理器中设置一个标志位来实现的。

  • 工作原理
    • 当 SMEP 启用时,如果处理器检测到当前正在特权级 0(内核模式)下执行用户模式内存中的代码(如从用户空间地址范围执行指令),会立即触发一个页错误异常(#PF)。
    • SMEP 通过强制内核只执行内核空间的代码,防止攻击者利用漏洞将恶意代码注入到用户空间,并试图在内核模式下执行。
  • 启用条件:在支持 SMEP 的处理器上,操作系统需要在 CR4 寄存器中设置 SMEP 位(CR4.SMEP = 1)。
  • 优势:提高系统安全性,防止内核态下运行未经授权的用户态代码,减少漏洞被利用的可能性(如 ROP 攻击)。

SMAP

Supervisor Mode Access Prevention (SMAP) 是进一步加强内核和用户空间隔离的一种机制。它控制内核模式对用户模式内存的访问权限。

  • 工作原理
    • 当 SMAP 启用时,操作系统内核在访问用户模式内存时必须明确允许访问(通常通过设置特定的访问标志或临时禁用 SMAP)。
    • 如果内核尝试在未授权的情况下访问用户模式内存,会触发一个页错误异常(#PF)。
  • 典型使用场景:内核有时需要合法访问用户空间内存(如系统调用中传递的用户数据)。在这种情况下,内核可以临时禁用 SMAP(通过 STAC 指令)进行访问,完成后再重新启用 SMAP(通过 CLAC 指令)。
  • 启用条件:在支持 SMAP 的处理器上,操作系统需要在 CR4 寄存器中设置 SMAP 位(CR4.SMAP = 1)。
  • 优势:进一步防止未授权的内存访问,增强内核空间与用户空间之间的隔离,防止某些类型的攻击(如恶意代码通过未授权的内存读写提升权限)。

注意注意:SMEP,SMAP是可以用户关闭的

DSE

绕过思路:开启测试模式

Driver Signature Enforcement (DSE) 是一种 Windows 操作系统中的安全机制,确保所有内核模式的驱动程序都经过微软的数字签名。

  • 工作原理
    • 在启用了 DSE 的系统上,加载到内核中的驱动程序必须经过微软签名,确保它们来自可信来源。
    • 未经签名或伪造签名的驱动程序将无法被操作系统加载,从而减少恶意软件或恶意驱动程序加载到系统中的风险。
  • 优势
    • 提高系统的整体安全性,防止未经验证的驱动程序导致系统不稳定或被恶意利用。
    • 保护操作系统的完整性,防止恶意软件通过驱动程序层进行攻击。
  • 绕过风险:在开发和调试环境中,有时开发人员可能会禁用 DSE(如使用测试签名模式),这可能会增加系统被恶意软件利用的风险。因此,在生产环境中强烈建议保持 DSE 启用。

4. PG(PatchGuard)

PatchGuard 是 Windows x64 操作系统中的一个内核安全机制,用于防止未经授权的修改操作系统内核结构。

  • 工作原理
    • PatchGuard 定期检查内核代码和关键数据结构的完整性(如系统服务描述符表 (SSDT)、中断描述符表 (IDT)、全局描述符表 (GDT) 等)。
    • 如果检测到任何未经授权的修改(如恶意软件试图在内核中进行钩子或修改关键数据结构),PatchGuard 会触发蓝屏(BSOD),以防止潜在的系统危害。
  • 优势
    • 保证了操作系统内核的完整性和稳定性。
    • 防止内核模式 rootkit 和其他低级恶意软件的攻击,这些攻击通常依赖于修改内核数据结构或代码路径。
  • 挑战:PatchGuard 也限制了合法的第三方安全软件和调试工具对内核的访问,因此这些工具需要找到兼容的方法来工作,而不会触发 PatchGuard。