浅谈 | Intel MPK
引言
Intel MPK(Memory Protection Keys) 是 Intel 推出的一种内存保护机制,可以在不修改页表的情况下,来控制线性地址所关联物理页的访问权限,本篇将说明一些基本用法和用途,在阅读本篇内容前,需要读者对 x86/x64 架构有基本的了解。
说明
CPUID.(EAX=07H,ECX=0H):ECX.OSPKE [bit 4])
- 判断系统是否支持 PKE
CPUID.(EAX=07H,ECX=0H):ECX.OSPKE [bit 4])
- 判断系统是否支持 PKS
CR4.PKE
- 控制是否启用 User-Mode(用户模式)页面的 Protection Keys
CR4.PKS
- 控制是否启用 Supervisor-Mode(管理模式)页面的 Protection Keys
PKRU
- 一个 32 位的内部寄存器,控制 User-Mode Protection Keys 所关联的页面权限
IA32_PKRS
- 一个 32 位的 MSR,控制 Supervisor-Mode Protection Keys 所关联的页面权限
RDPKRU
- 读取 PKRU 内部寄存器
WRPKRU
- 写入 PKRU 内部寄存器
Protection Key
在禁用 CR4.PKE 的情况下,用户模式页表中的 Bit 59 ~ Bit62
是保留位
在启用 CR4.PKE 的情况下,用户模式页表中的 Bit 59 ~ Bit62
是 Protection Key
在禁用 CR4.PKS 的情况下,管理模式页表中的 Bit 59 ~ Bit62
是保留位
在启用 CR4.PKS 的情况下,管理模式页表中的 Bit 59 ~ Bit62
是 Protection Key
这 4 位的 Protection Key 范围是 0~15,相当于是一个索引,被关联到 PKRU 或 PKRS
PKRU
这个寄存器类似于一个位图,存放着 16 对 ADi 与 WDi,用于控制与 User-Mode Protection Key 关联的页面权限,这个寄存器需要通过RDPKRU
WRPKRU
XSAVE
XRSTOR
进行控制。
- ADi = 1,不允许任何数据访问
- WDi = 1,不允许用户模式数据写入(在 CR0.WP 复位的情况下管理模式可以写入)
- 取指操作不受 PKRU 影响
IA32_PKRS
这个寄存器结构与 PKRU 极其相似,区别在于它所控制的是 Supervisor-Mode Protection Keys,并且此寄存器是一个 MSR 寄存器,高 32 位为保留位,需要通过RDMSR
WRMSR
进行控制。
- ADi = 1,不允许任何数据访问
- WDi = 1,不允许用户模式数据写入(在 CR0.WP 复位的情况下管理模式可以写入)
- 取指操作不受 PKRS 影响
PageFault
如果是由 Protection Keys 引发的#PF,那么 PFEC 的 Bit 5
则置位。
流程
- 首先,判断处理器是否支持 PKE 或 PKS
- 如果支持,则置位 CR4.PKE 或 PKS
- 通过
WRPKRU
将权限写入到 PKRU,或者通过WRMSR
将权限写入到 PKRS- 例子:如果 Protection Key 设置为
0Fh(1111b)
,那么所对应的掩码就是0C0000000h
- 例子:如果 Protection Key 设置为
- 然后修改页表条目中的 Protection Key,将它与 PKRU 或 PKRS 关联
结尾
聪明的挂哥,可能已经看到加粗的几个字了,取指操作不受 Protection Key 影响,意味着可以分离读写与执行,可以分离读写就意味着,在使用所谓的 无痕HOOK
的时候,性能可以大幅度提高。
聪明的挂哥都知道,Intel VT-x 提供的 EPT 可以轻松的完成这项任务,但是 AMD-V 提供的 NPT 并没有这样的功能,那么结合 Protection Key 是否可以间接的为 AMD-V 提供这样的功能来平替 EPT,来完成所谓的 无痕HOOK
呢?
答案就在下面,诸位细品。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nt!_HARDWARE_PTE
+0x000 Valid : Pos 0, 1 Bit
+0x000 Write : Pos 1, 1 Bit
+0x000 Owner : Pos 2, 1 Bit
+0x000 WriteThrough : Pos 3, 1 Bit
+0x000 CacheDisable : Pos 4, 1 Bit
+0x000 Accessed : Pos 5, 1 Bit
+0x000 Dirty : Pos 6, 1 Bit
+0x000 LargePage : Pos 7, 1 Bit
+0x000 Global : Pos 8, 1 Bit
+0x000 CopyOnWrite : Pos 9, 1 Bit
+0x000 Prototype : Pos 10, 1 Bit
+0x000 reserved0 : Pos 11, 1 Bit
+0x000 PageFrameNumber : Pos 12, 40 Bits
+0x000 SoftwareWsIndex : Pos 52, 11 Bits
+0x000 NoExecute : Pos 63, 1 Bit