SKREAM(二):内存地址的随机分配
字数 1854 2025-08-19 12:42:38

SKREAM技术:内存地址随机分配防御机制详解

0x01 关于SKREAM技术背景

SKREAM是一种针对Windows内核池溢出漏洞的防御工具包,在前一篇文章中已经讨论了针对Windows 7和8系统的内核池溢出缓解技术。虽然Windows 8.1已经缓解了特定攻击手法(如在0xbad0b0b0构建恶意OBJECT_TYPE结构),但内存溢出漏洞仍然存在且攻击手法不断进化。

溢出攻击的必要前提条件

  1. 攻击者必须找到关键地址构建溢出缓冲区
  2. 必须准确知道应写入哪些数据
  3. 必须保持其余数据不变
  4. 需要精确计算ObjectHeader从溢出缓冲区开始的准确距离和TypeIndex偏移量

0x02 PoolSlider(内存隔离)技术

技术原理

  • x64架构内存分配器分配的字节长度必须对齐到16字节(x86为8字节)
  • 不足16字节整数倍的请求会被填充字符串以达到对齐要求
  • 通过随机化返回给调用者的指针位置,混淆内存池开头的填充字节

实现机制

  1. 监听图像加载事件并在每个新加载驱动的ExAllocatePoolWithTag上放置IAT钩子
  2. 计算需要填充的字节数
  3. 生成1到可用填充量之间的随机数n
  4. 将返回给调用者的指针向前推进n位

内存释放处理

  • 在ExFreePoolWithTag上放置IAT钩子
  • 释放前将指针重新对齐到16字节边界
  • 防止因指针不对齐导致的BAD_POOL_HEADER错误

技术挑战与解决方案

  1. 分配/释放函数不匹配问题

    • 同时在ExAllocatePool和ExFreePool上放置钩子
    • 在Ex{Allocate,Free}PoolWithTag处进行同样的随机/重新对齐处理
  2. 字符串分配释放问题

    • 在RtlFree{Ansi,Unicode}String上放置IAT钩子
    • 使用与ExFreePool(WithTag)相同的手法重新对齐指针
  3. 跨驱动分配释放问题

    • 当一个驱动分配内存遇上另一个驱动(如NTOS)释放内存时
    • 目前尚无完美解决方案,可能导致0xC2错误
  4. 无填充字节情况

    • 当请求大小正好是16的整数倍时无法推进指针
    • 可能的解决方案:人为添加1字节请求,强制产生15字节填充

0x03 PoolBloater(资源浪费者)技术

技术原理

  • 不改变分配的基本地址
  • 随机增加请求池分配的大小("膨胀")
  • 通过破坏攻击精度来防御溢出

实现优势

  1. 实现简单,只需在ExAllocatePool(WithTag)放置钩子
  2. 不需要处理指针对齐问题
  3. 有效避免内存碰撞问题
  4. 溢出大小随机化使攻击难以预测

技术缺点

  1. 内存占用率可能显著增加
  2. 需要在防御效果和资源占用之间权衡:
    • 设置较高上限:防御效果好但资源占用大
    • 设置较低下限:资源占用少但防御效果差

0x04 技术测试与验证

使用HEVD(HackSys Extreme Vulnerable Driver)测试

  1. PoolSlider技术测试结果:

    • 返回给调用者的指针被移动(如图5.1中移动5字节)
    • 溢出无法正确覆盖下一个池块头(图5.2)
    • 最终因破坏池头完整性导致崩溃(图5.3)
  2. 防御效果对比:

    • 有SKREAM时溢出被有效阻止(图7上图)
    • 无SKREAM时溢出成功(图7下图)

0x05 技术局限性

当前版本的限制

  1. 仅能保护非Windows操作系统的一部分驱动程序
  2. 仅能保护在SKREAM之后加载的驱动
  3. 仅能保护通过ExAllocatePool(WithTag)直接执行的内存分配
  4. 无法保护系统自身的内存分配(如IOCTLs中的SystemBuffer)
  5. 仅能保护与文中描述相似的分配方式(大跨度分配由nt!ExpAllocateBigPool处理)

部署注意事项

  1. 直接卸载SKREAM可能导致系统崩溃
  2. 启用内存隔离技术时,SKREAM服务不能伴随系统启动,只能自启

0x06 技术实现要点总结

PoolSlider关键点

  1. 随机化指针位置破坏攻击可预测性
  2. 必须正确处理内存释放时的对齐问题
  3. 需要处理各种特殊情况(字符串分配、跨驱动操作等)

PoolBloater关键点

  1. 通过随机增加分配大小破坏攻击精度
  2. 实现简单但资源消耗较大
  3. 需要在防御强度和资源消耗间找到平衡点

0x07 未来发展方向

  1. 扩大保护范围至更多系统组件
  2. 解决跨驱动分配释放问题
  3. 优化资源消耗问题
  4. 开发更安全的部署和卸载机制
  5. 探索不放钩子的防御实现方式

通过这两种技术,SKREAM为内核池溢出攻击提供了有效的防御机制,尽管目前还存在一些限制,但已经显著提高了攻击者利用此类漏洞的难度。

SKREAM技术:内存地址随机分配防御机制详解 0x01 关于SKREAM技术背景 SKREAM是一种针对Windows内核池溢出漏洞的防御工具包,在前一篇文章中已经讨论了针对Windows 7和8系统的内核池溢出缓解技术。虽然Windows 8.1已经缓解了特定攻击手法(如在0xbad0b0b0构建恶意OBJECT_ TYPE结构),但内存溢出漏洞仍然存在且攻击手法不断进化。 溢出攻击的必要前提条件 攻击者必须找到关键地址构建溢出缓冲区 必须准确知道应写入哪些数据 必须保持其余数据不变 需要精确计算ObjectHeader从溢出缓冲区开始的准确距离和TypeIndex偏移量 0x02 PoolSlider(内存隔离)技术 技术原理 x64架构内存分配器分配的字节长度必须对齐到16字节(x86为8字节) 不足16字节整数倍的请求会被填充字符串以达到对齐要求 通过随机化返回给调用者的指针位置,混淆内存池开头的填充字节 实现机制 监听图像加载事件并在每个新加载驱动的ExAllocatePoolWithTag上放置IAT钩子 计算需要填充的字节数 生成1到可用填充量之间的随机数n 将返回给调用者的指针向前推进n位 内存释放处理 在ExFreePoolWithTag上放置IAT钩子 释放前将指针重新对齐到16字节边界 防止因指针不对齐导致的BAD_ POOL_ HEADER错误 技术挑战与解决方案 分配/释放函数不匹配问题 同时在ExAllocatePool和ExFreePool上放置钩子 在Ex{Allocate,Free}PoolWithTag处进行同样的随机/重新对齐处理 字符串分配释放问题 在RtlFree{Ansi,Unicode}String上放置IAT钩子 使用与ExFreePool(WithTag)相同的手法重新对齐指针 跨驱动分配释放问题 当一个驱动分配内存遇上另一个驱动(如NTOS)释放内存时 目前尚无完美解决方案,可能导致0xC2错误 无填充字节情况 当请求大小正好是16的整数倍时无法推进指针 可能的解决方案:人为添加1字节请求,强制产生15字节填充 0x03 PoolBloater(资源浪费者)技术 技术原理 不改变分配的基本地址 随机增加请求池分配的大小("膨胀") 通过破坏攻击精度来防御溢出 实现优势 实现简单,只需在ExAllocatePool(WithTag)放置钩子 不需要处理指针对齐问题 有效避免内存碰撞问题 溢出大小随机化使攻击难以预测 技术缺点 内存占用率可能显著增加 需要在防御效果和资源占用之间权衡: 设置较高上限:防御效果好但资源占用大 设置较低下限:资源占用少但防御效果差 0x04 技术测试与验证 使用HEVD(HackSys Extreme Vulnerable Driver)测试 PoolSlider技术测试结果: 返回给调用者的指针被移动(如图5.1中移动5字节) 溢出无法正确覆盖下一个池块头(图5.2) 最终因破坏池头完整性导致崩溃(图5.3) 防御效果对比: 有SKREAM时溢出被有效阻止(图7上图) 无SKREAM时溢出成功(图7下图) 0x05 技术局限性 当前版本的限制 仅能保护非Windows操作系统的一部分驱动程序 仅能保护在SKREAM之后加载的驱动 仅能保护通过ExAllocatePool(WithTag)直接执行的内存分配 无法保护系统自身的内存分配(如IOCTLs中的SystemBuffer) 仅能保护与文中描述相似的分配方式(大跨度分配由nt !ExpAllocateBigPool处理) 部署注意事项 直接卸载SKREAM可能导致系统崩溃 启用内存隔离技术时,SKREAM服务不能伴随系统启动,只能自启 0x06 技术实现要点总结 PoolSlider关键点 随机化指针位置破坏攻击可预测性 必须正确处理内存释放时的对齐问题 需要处理各种特殊情况(字符串分配、跨驱动操作等) PoolBloater关键点 通过随机增加分配大小破坏攻击精度 实现简单但资源消耗较大 需要在防御强度和资源消耗间找到平衡点 0x07 未来发展方向 扩大保护范围至更多系统组件 解决跨驱动分配释放问题 优化资源消耗问题 开发更安全的部署和卸载机制 探索不放钩子的防御实现方式 通过这两种技术,SKREAM为内核池溢出攻击提供了有效的防御机制,尽管目前还存在一些限制,但已经显著提高了攻击者利用此类漏洞的难度。