Abusing Windows Physical
字数 2481 2025-08-24 10:10:13

Windows 物理地址滥用技术深入解析

引言

本文档详细解析了Windows系统中物理地址(Physical Address)的利用技术,这种技术在多个内核漏洞利用中发挥了关键作用,如SMBleeding (CVE-2020-0796)、CVE-2020-1206和CVE-2018-1038等。通过深入理解Windows内存管理机制,攻击者可以绕过多种安全防护措施。

Windows内核安全机制背景

Windows Vista以来引入的多项安全机制:

  1. NX/DEP:内核模式下区分data和code,通过保护模式内存分段实现内存属性标记
  2. KALSR:内核地址空间布局随机化,随机化Windows模块基地址
  3. Integrity Levels:可信级别机制限制高风险程序执行敏感操作
  4. SMEP:超级模式执行保护,禁止内核空间执行用户空间代码

Windows内存分页单位

  • 1KB = 0x400B
  • 1MB = 1KB * 0x400
  • 1GB = 1MB * 0x400
  • 1TB = 1GB * 0x400

Intel分页机制

x86架构(32位)

  • 两级寻址机制:PAGE DIRECTORY和PAGE TABLE
  • CR3寄存器指向当前PAGE DIRECTORY的物理地址
  • 每个PAGE DIRECTORY有1024个PDE(Page Directory Entry)
  • 每个PDE指向一个PAGE TABLE的物理地址
  • 每个PAGE TABLE有1024个PTE(Page Table Entry)
  • 每个PTE映射4KB物理地址

特殊情况下,PDE可以指向4MB的Large Page(PS标记)

PAE(物理地址扩展)

  • 引入PDPT(Page Directory Pointer Table)
  • 物理地址扩展到36位(64GB寻址空间)
  • PDPT有512个PDPTE,每个指向1GB空间
  • 引入NX bit区分data和code

x64架构(64位)

  • 使用48位物理地址(64位虚拟地址)
  • 引入Canonical Address概念(0-0x7FFFFFFFFFFFF和0xFFFF800000000000-0xFFFFFFFFFFFFFFFF)
  • 四级页表寻址:PML4、PDPT、PAGE DIRECTORY、PAGE TABLE
  • 寻址计算:512PML4Es * 512PDPTEs * 512PDEs * 512PTEs * 4KB = 256TB

自引用条目技术(Self-ref Entry)

技术原理

将最高级别页表中的某一entry指向该页表自身:

  • 32位:self-entry存在于PAGE DIRECTORY
  • 64位:self-entry存在于PML4

实现方式

假设:

  • entry 0x00 → User Space
  • entry 0x100 → self-ref
  • entry 0x1ff → Kernel Space

内存分布:

  • User Space: 0 ~ 0x7fffffffffff
  • Memory Management: 0xffff800000000000 ~ 0xffff800000000000
  • Kernel Space: 0xffffff8000000000 ~ 0xffffffffffffffff

计算物理地址的Python函数

def calc_physical_64(virtual_addr):
    entry_size = 0x8
    shift_address = virtual_addr >> 12  # 4kb
    pte_offset = shift_address & 0x1ff
    shift_address = shift_address >> 9  # 512
    pde_offset = shift_address & 0x1ff
    shift_address = shift_address >> 9  # 512
    pdpt_offset = shift_address & 0x1ff
    shift_address = shift_address >> 9
    pml_offset = shift_address & 0x1ff
    print("entry: PML4: 0x%x PDPT: 0x%x PD: 0x%x PT: 0x%x" % 
          (pml_offset, pdpt_offset, pde_offset, pte_offset))
    print("offset: PML4: 0x%x PDPT: 0x%x PD: 0x%x PT: 0x%x" % 
          (pml_offset*entry_size, pdpt_offset*entry_size, 
           pde_offset*entry_size, pte_offset*entry_size))

def calc_physical_32(virtual_addr):
    entry_size = 0x8
    shift_address = virtual_addr >> 12  # 4kb
    pte_offset = shift_address & 0x1ff
    shift_address = shift_address >> 9  # 512
    pde_offset = shift_address & 0x1ff
    print("entry: PD: 0x%x PT: 0x%x" % (pde_offset, pte_offset))
    print("offset: PD: 0x%x PT: 0x%x" % (pde_offset*entry_size, pte_offset*entry_size))

Windows实现细节

  • 64位系统中:前256个PML4条目用于用户空间,后256个用于内核空间
  • PML4的self-ref entry是0x1ED(内核空间)
  • 对应的虚拟地址空间:(512G + 1G + 2M + 4K)*0x1ED = 0xf6fb7dbed000
  • 加上canonical address:0xfffff6fb7dbed000

安全弱点

  • Windows为所有进程使用固定的PML4 self-ref entry
  • 攻击者可计算Page Table/entries
  • 可修改或添加entries
  • 影响KALSR,可用于SMEP绕过

Windows 1607更新

引入了随机化Self-Ref Entry的措施

Windows HAL堆

  • HAL.dll(硬件抽象层)是开机时第一个加载的模块
  • HAL堆地址在启动时创建,总是映射到固定虚拟地址:
    • 32位:0xffd00000
    • 64位:0xfffffffffd000000
  • 这一特性可用于绕过KALSR

实践验证

测试代码

#include <Windows.h>
#include <wchar.h>

int main() {
    PVOID addr = (PVOID)0x1000000;
    //Allocate Memory
    addr = VirtualAlloc(addr, 0x1000, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    wprintf(L"address = 0x%llx\n", addr);
    // Setting Memory
    memset(addr, 0x41, 0x1000);
    // Debug
    __debugbreak();
}

Windows 7 32位实验结果

  1. 成功分配虚拟地址并写入数据
  2. 32位系统只有PDE和PTE
  3. PTE用物理地址0x61cd5000映射虚拟地址0x1000000
  4. 修改PTE可改变虚拟地址内容
  5. 通过修改PTE可实现两个虚拟地址共享同一物理地址
  6. 计算出的PTE偏移正确,但缺少PTE基地址
  7. Windows 7中Self-Ref没有随机化

Windows 10 1903 64位实验结果

  1. 四级页表寻址机制
  2. PTE保存虚拟地址对应的物理地址内容
  3. 修改PTE效果与Win7相同
  4. 计算出的Page Table偏移正确
  5. Windows 10及以上版本存在:
    • nt!MiGetPteAddress(Pte基地址编码在固定偏移0x13)
    • MiGetPdeAddress(偏移0xc)
  6. Windows 10中PTE基地址是随机的

利用技术总结

  1. 任意地址写利用:通过修改可控虚拟地址的PTE指向目标物理地址
  2. 共享物理地址:使两个虚拟地址指向同一物理地址,通过可控地址修改不可控地址
  3. 绕过KALSR:利用HAL堆固定地址或计算Page Table地址
  4. SMEP绕过:通过物理地址操作在内核空间执行用户空间代码

相关链接

  • CSW2016会议资料
  • Windows内核文档
  • Intel架构手册

防御建议

  1. 保持系统更新(特别是1607及以上版本)
  2. 启用所有内存保护机制
  3. 监控异常的内存操作
  4. 限制对关键内存区域的访问

通过深入理解这些技术,安全研究人员可以更好地防御相关攻击,同时也能开发更有效的漏洞利用方法。

Windows 物理地址滥用技术深入解析 引言 本文档详细解析了Windows系统中物理地址(Physical Address)的利用技术,这种技术在多个内核漏洞利用中发挥了关键作用,如SMBleeding (CVE-2020-0796)、CVE-2020-1206和CVE-2018-1038等。通过深入理解Windows内存管理机制,攻击者可以绕过多种安全防护措施。 Windows内核安全机制背景 Windows Vista以来引入的多项安全机制: NX/DEP :内核模式下区分data和code,通过保护模式内存分段实现内存属性标记 KALSR :内核地址空间布局随机化,随机化Windows模块基地址 Integrity Levels :可信级别机制限制高风险程序执行敏感操作 SMEP :超级模式执行保护,禁止内核空间执行用户空间代码 Windows内存分页单位 1KB = 0x400B 1MB = 1KB * 0x400 1GB = 1MB * 0x400 1TB = 1GB * 0x400 Intel分页机制 x86架构(32位) 两级寻址机制:PAGE DIRECTORY和PAGE TABLE CR3寄存器指向当前PAGE DIRECTORY的物理地址 每个PAGE DIRECTORY有1024个PDE(Page Directory Entry) 每个PDE指向一个PAGE TABLE的物理地址 每个PAGE TABLE有1024个PTE(Page Table Entry) 每个PTE映射4KB物理地址 特殊情况下,PDE可以指向4MB的Large Page(PS标记) PAE(物理地址扩展) 引入PDPT(Page Directory Pointer Table) 物理地址扩展到36位(64GB寻址空间) PDPT有512个PDPTE,每个指向1GB空间 引入NX bit区分data和code x64架构(64位) 使用48位物理地址(64位虚拟地址) 引入Canonical Address概念(0-0x7FFFFFFFFFFFF和0xFFFF800000000000-0xFFFFFFFFFFFFFFFF) 四级页表寻址:PML4、PDPT、PAGE DIRECTORY、PAGE TABLE 寻址计算:512PML4Es * 512PDPTEs * 512PDEs * 512PTEs * 4KB = 256TB 自引用条目技术(Self-ref Entry) 技术原理 将最高级别页表中的某一entry指向该页表自身: 32位:self-entry存在于PAGE DIRECTORY 64位:self-entry存在于PML4 实现方式 假设: entry 0x00 → User Space entry 0x100 → self-ref entry 0x1ff → Kernel Space 内存分布: User Space: 0 ~ 0x7fffffffffff Memory Management: 0xffff800000000000 ~ 0xffff800000000000 Kernel Space: 0xffffff8000000000 ~ 0xffffffffffffffff 计算物理地址的Python函数 Windows实现细节 64位系统中:前256个PML4条目用于用户空间,后256个用于内核空间 PML4的self-ref entry是0x1ED(内核空间) 对应的虚拟地址空间:(512G + 1G + 2M + 4K)* 0x1ED = 0xf6fb7dbed000 加上canonical address:0xfffff6fb7dbed000 安全弱点 Windows为所有进程使用固定的PML4 self-ref entry 攻击者可计算Page Table/entries 可修改或添加entries 影响KALSR,可用于SMEP绕过 Windows 1607更新 引入了随机化Self-Ref Entry的措施 Windows HAL堆 HAL.dll(硬件抽象层)是开机时第一个加载的模块 HAL堆地址在启动时创建,总是映射到固定虚拟地址: 32位:0xffd00000 64位:0xfffffffffd000000 这一特性可用于绕过KALSR 实践验证 测试代码 Windows 7 32位实验结果 成功分配虚拟地址并写入数据 32位系统只有PDE和PTE PTE用物理地址0x61cd5000映射虚拟地址0x1000000 修改PTE可改变虚拟地址内容 通过修改PTE可实现两个虚拟地址共享同一物理地址 计算出的PTE偏移正确,但缺少PTE基地址 Windows 7中Self-Ref没有随机化 Windows 10 1903 64位实验结果 四级页表寻址机制 PTE保存虚拟地址对应的物理地址内容 修改PTE效果与Win7相同 计算出的Page Table偏移正确 Windows 10及以上版本存在: nt !MiGetPteAddress(Pte基地址编码在固定偏移0x13) MiGetPdeAddress(偏移0xc) Windows 10中PTE基地址是随机的 利用技术总结 任意地址写利用 :通过修改可控虚拟地址的PTE指向目标物理地址 共享物理地址 :使两个虚拟地址指向同一物理地址,通过可控地址修改不可控地址 绕过KALSR :利用HAL堆固定地址或计算Page Table地址 SMEP绕过 :通过物理地址操作在内核空间执行用户空间代码 相关链接 CSW2016会议资料 Windows内核文档 Intel架构手册 防御建议 保持系统更新(特别是1607及以上版本) 启用所有内存保护机制 监控异常的内存操作 限制对关键内存区域的访问 通过深入理解这些技术,安全研究人员可以更好地防御相关攻击,同时也能开发更有效的漏洞利用方法。