搞定PatchGuard:利用KPTI绕过内核修改保护
字数 1708 2025-08-19 12:41:44
利用KPTI绕过Windows PatchGuard内核修改保护技术分析
0x00 前言
本文详细分析了一种利用KPTI(Kernel Page Table Isolation)机制绕过Windows PatchGuard内核修改保护的技术。该技术由ensilo团队发现并于2018年报告给微软,微软在Windows 10 RS5中引入了修复补丁。
0x01 技术背景
1.1 推测执行漏洞
- Meltdown(恶意数据缓存加载):利用指令执行与权限检查之间的CPU竞争条件
- Spectre:利用分支预测和推测执行特性
- 这些漏洞源自CPU硬件层面的侧信道缺陷
1.2 KPTI(内核页表隔离)
- 软件缓解措施,需要大幅修改操作系统内核
- Windows实现称为KVAS(Kernel Virtual Address Shadow)
- 进程虚拟地址空间被分割为两个页表:
- 内核模式页表:映射完整地址空间(用户+内核)
- 用户模式页表:仅映射ring 3及ring 0转换所需的最小内核空间
0x02 KVAS实现细节
2.1 内存管理
- KVASCODE section(位于ntoskrnl.exe):
- 被映射到用户及内核页表的相同虚拟地址
- 包含内核处理器控制块(KPRCB)末尾的栈空间及专用区域
- 用户地址空间在两个页表间共享
- 不同页表中的不同PML4表项指向相同的PDP表实现共享
2.2 权限转换流程
- ring 3到ring 0转换新增间接跳转环节
- 转换代码检查当前页表:
- 若为用户页表,则切换到内核页表
- 返回ring 3时执行相反操作
0x03 绕过PatchGuard原理
3.1 PatchGuard局限性
- 传统上监控ntoskrnl、HAL、NDIS代码及关键结构(IDT、SSDT)
- ring 3到ring 0转换的第一条和最后一条指令现在在用户页表中执行
- 用户页表中的内核地址空间对PatchGuard透明
3.2 技术实现步骤
3.2.1 访问用户页表
- 内核模式下获取用户页表物理地址:
- 通过
EPROCESS.Pcb.UserDirectoryTableBase - 或直接读取CR3寄存器
- 通过
- 使用PTE重映射和页表遍历技术完全控制用户页表
3.2.2 Hook技术实现
-
内存管理:
- 修改用户页表,使KVASCODE虚拟地址映射到不同物理页面
- 不修改ntoskrnl实际页面,避免PatchGuard检测
-
代码执行:
- 在用户页表中映射额外页面
- 创建CR3分配gadget,其ret指令在两个地址空间中重合
- 修改代码逻辑,压入驱动地址并跳转到CR3分配gadget
3.2.3 处理VBS(Virtualization Based Security)
- HVCI(HyperVisor代码完整性):
- 阻止运行未签名代码
- 需在驱动中预编译hook代码
- 需预先知道函数位置或使用固定偏移存储数据结构
- VBS主机使用
int 2e指令而非syscall/sysenter
0x04 缓解措施
微软修复方案:
- PatchGuard应检查内核和用户页表中KVASCODE页面PTE的PFN是否相同
- 确保最小内核地址空间代码与实际内核空间代码匹配
0x05 影响范围
- 最初在Windows 10 RS4 x64验证
- 适用于所有支持KVAS的Windows版本(Win7/8.1及相应服务器版)
- 技术原理可应用于其他使用KPTI的系统(Linux/macOS)
0x06 防御建议
- 确保系统更新至Windows 10 RS5或更高版本
- 启用VBS和HVCI提供额外保护
- 监控异常的内核内存修改行为
附录:关键技术点总结
| 技术点 | 描述 |
|---|---|
| KVAS | Windows的KPTI实现,分割用户/内核页表 |
| KVASCODE | 包含权限转换代码的特殊section |
| PTE重映射 | 修改用户页表映射关系的关键技术 |
| CR3分配gadget | 实现跨页表控制流转移的核心组件 |
| HVCI限制 | 要求hook代码必须预编译和签名 |