-
-
[原创]与磁盘校验 ntoskrnl.exe 的内存完整性技术总结 (有代码)
-
发表于: 2025-3-24 00:30 2325
-
Windows内核安全: 与磁盘校验 ntoskrnl.exe 的内存完整性
本文实验环境: Windows 11 23H2 (Microsoft Windows 版本 10.0.22631.5039)
来自: 既视感安全实验室
运行成功图片:
背景介绍
在Windows内核环境中,恶意行为通常从篡改系统关键数据开始,包括对ntoskrnl.exe的修改。即使在KPP(PatchGuard)执行的情况下,篡改仍有可能发生,主要有两种情况:
- PatchGuard检测延迟:PatchGuard对篡改的防护并非实时的,存在一定延迟。恶意软件可能在关键流程前对ntoskrnl.exe执行篡改然后快速还原,影响执行流程。
- 引导阶段修补:一些恶意软件可作为UEFI Bootkit,在内核完全启动前就修补ntoskrnl.exe,这样PatchGuard会将修补视为合法,不会触发蓝屏。
因此,在执行关键操作前验证系统核心组件是Windows内核安全的基础建设。一种常见方法是将内存中的映像与磁盘文件进行对比校验。
内存与磁盘中ntoskrnl.exe的差异
磁盘文件与内存映像存在多种差异,需要在校验前考虑:
差异类型 | 描述 |
---|---|
加载地址 | 内存中的基址与磁盘文件不同 |
重定位项 | 地址已根据实际加载位置调整 |
特殊节段 | INIT、.rsrc、GFIDS等节在内存中可能被修改或释放 |
热修补 | Windows引导加载器可能修改固定地址代码 |
Spectre 缓解 | 从Windows 10 1809开始的Retpoline实现 |
SSDT | KeServiceDescriptorTable中的表被压缩处理 |
完整性校验处理方法
基本流程
- 将磁盘文件中的节段数据按照VirtualAddress复制到相应位置
- 根据内核中ntoskrnl.exe的基地址对数据进行重定位
- 找到KeServiceDescriptorTable地址,模拟KeCompactServiceTable逻辑处理表数据
- 识别并允许Spectre缓解机制的合法修改
- 跳过不需要校验的特定节段
KeServiceDescriptorTable处理
KiServiceTable(SSDT表)和KiArgumentTable在加载后会被nt!KeCompactServiceTable
函数压缩,核心逻辑如下:
1 2 3 | FunctionCookie = ( UHALF_PTR )*( PUHALF_PTR )(ServiceTableBase + Index * 4) - ( UHALF_PTR )ServiceTableBase + ( UHALF_PTR )NewImageBase; *Pointer = (16 * FunctionCookie) | (ArgumentCookie >> 2); |
在重定位后,应定位KiServiceTable和KiArgumentTable,然后模拟此逻辑对数据进行压缩。
不校验的节段
以下节段在校验过程中应排除:
- 所有可写节段
- GFIDS (用于控制流保护)
- MINIEX (用于Minidump机制)
- INIT (初始化完成后会被释放)
- .rsrc 和 .reloc (系统会修改)
注:虽然本文未校验.idata和.edata,但实际应用中应考虑更详细的校验导入表和导出表的数据。
热修补处理
Windows 10中页表相关地址被随机化,但ntoskrnl.exe代码中这些地址不是动态获取的,而是通过Windows引导加载程序热修补为正确地址。
检测到的常见热修补包括但不限于:
原始固定地址 | 被替换为 |
---|---|
0xFFFFF68000000000 | PteBase |
0xFFFFF6FB40000000 | PdeBase |
0xFFFFF6FB7DA00000 | PdptBase |
0xFFFFF6FB7DBED000 | Pml4Base |
0x0FFFFDE0000000000 | MmPfnDataBase |
0x0FFFFF6FB7DBEDF68 | SystemPteAddress |
其中SystemPteAddress定义如下:
1 2 3 4 5 | ULONG64 SystemCr3 = __readcr3(); PHYSICAL_ADDRESS PhysicalCr3{}; PhysicalCr3.QuadPart = SystemCr3; ULONG64 VirtualCr3 = ( ULONG64 )MmGetVirtualForPhysical(PhysicalCr3); ULONG64 SystemPteAddress = ( ULONG64 )MiGetPteAddress(PteBase, VirtualCr3); |
在本文版本中具体的替换对如下:
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 | // Create replacement array ReplacementPair Replacements[] = { { 0x0FFFFF6FB7DBEDF68, SystemPteAddress }, { 0x0FFFFF68000000000, PteBase }, { 0x0FFFFF6FFFFFFFFFF, PteBase | 0xFFFFFFFFFF }, { 0x0FFFFDE0000000000, MmPfnDataBase }, { 0x0FFFFDE0000000008, MmPfnDataBase + 0x08 }, { 0x0FFFFDE0000000010, MmPfnDataBase + 0x10 }, { 0x0FFFFDE0000000018, MmPfnDataBase + 0x18 }, { 0x0FFFFDE0000000022, MmPfnDataBase + 0x22 }, { 0x0FFFFDE0000000020, MmPfnDataBase + 0x20 }, { 0x0FFFFDE0000000023, MmPfnDataBase + 0x23 }, { 0x0FFFFDE0000000028, MmPfnDataBase + 0x28 }, { 0x0FFFFDE0000000030, MmPfnDataBase + 0x30 }, { 0x0FFFFDE0000000FFF, MmPfnDataBase + 0xFFF }, { 0x0FFFFF6FB7DBED000, Pml4Base }, { 0x0FFFFF6FB7DBED7F8, Pml4Base + 0x7F8 }, { 0x0FFFFF6FB7DBED800, Pml4Base + 0x800 }, { 0x0FFFFF6FB7DBEDFFF, Pml4Base + 0xFFF }, { 0x0FFFFF6FB7DA00000, PdptBase }, { 0x0FFFFF6FB40000000, PdeBase }, { 0x0FFFFF6FB5FFFFFF8, PdeBase + 0x1FFFFFF8 }, { 0x0FFFFF6FB7FFFFFFF, PdeBase + 0x3FFFFFFF }, { 0x0FFFFF68000000008, PteBase + 0x08 }, { 0x0FFFFF68000000FFF, PteBase + 0xFFF }, { 0x0FFFFF70000000000, PteBase + 0x8000000000 }, }; |
Spectre 缓解 处理
从Windows 10 1809开始,Microsoft实施了针对Spectre漏洞的缓解措施,通过运行时修补内核代码来实现 Retpoline 技术。
典型的修补模式是将间接调用转换为直接调用到特定的防护函数。需要使用反汇编引擎(如hde64)检查指令模式,确认是否为合法的Spectre缓解修补。
结语
本文讨论的技术可基本实现对ntoskrnl.exe的完整性校验,但作为安全产品的完整方案还远远不够。为确保关键执行流程的安全,还需对更多系统组件执行更复杂的校验。
参考资料
- 年经贴 SSDT与Shadow SSDT的遍历与恢复-编程技术-看雪-安全社区|安全招聘|kanxue.com
- 19.x64下算出PTE_windows x64 pte-CSDN博客
- Mitigating Spectre variant 2 with Retpoline on Windows | Microsoft Community Hub
- Bootkits and kernel patching - Samuel Tulach
- Kernel Patch Protection - Wikipedia