深入解析Patchguard:基于Hypervisor的内省检测技术(第一部分)

本文详细解析微软Patchguard如何检测基于Hypervisor的内省攻击,包括KiErrata704Present、KiErrataSkx55Present和KiErrata361Present等机制的运作原理,涉及SYSCALL、单步异常和特权软件异常等底层技术。

Patchguard: 基于Hypervisor的内省检测 [第一部分]

在过去的2-3年里,微软在Patchguard中插入了多种虚拟化内省检测方法(高级术语)。这并不令人意外,因为当攻击者代码在更高特权级别运行时,颠覆内核补丁保护易如反掌。虽然Windows在Hypervisor下运行良好,并具有开放的半虚拟化接口,但Patchguard正在寻找虚拟机监控程序(vmm)篡改非功能性虚拟机必需状态的迹象。例如,通过隐藏控制分支目标的MSR真实值来挂钩系统调用,或利用嵌套分页在关键控制路径上获得执行。

尽管Patchguard包含比本文介绍的更多的检测机制,作者选择了他最喜欢的机制,因为它们具有特殊性。读者可以自行寻找更多机制。本文旨在帮助安全软件、反病毒和内省工具与内核补丁保护实现互操作性。

首先介绍的是KiErrata704Present。乍一看,这些函数的命名约定似乎无害,对于未经训练的眼睛,可能看起来像是在合法检查某种meme errata。让我们分解这个函数:

背景知识:某些古老的权限转换形式,如SYSENTER和调用门,允许调用者本质上单步执行操作码。这并不理想,因为单步#DB会在分支完成后传递。内核需要记录这一点,以便在处理系统调用后IRET到调用者,继续单步操作。SYSCALL/SYSRET的引入通过FMASK MSR解决了这个问题。该MSR让操作系统开发人员更好地控制SYSCALL执行时如何处理RFLAGS。任何合理的操作系统都会确保IF和TF被该MSR屏蔽。此外,SYSRET经过特殊设计,如果加载的RFLAGS映像设置了TF,它将在下一条指令边界引发#DB,而不是像IRET那样应用于分支目标后的边界。这允许在单步执行SYSCALL指令时获得平滑的用户模式调试体验。希望我们现在有了更好的理解,可以看到KiErrata704Present做的第一件事是保存FMASK MSR内容,然后设置MSR值,使得TF不会被SYSCALL操作修改。

接下来我们看到一系列PUSHFQ/POPFQ设置陷阱标志并将其加载回RFLAGS寄存器。如你所知,这将导致前一条指令在执行期间设置TF,并在其边界触发#DB。当然,除非该指令属于软件异常、软件中断或特权软件异常类,或者指令生成硬件异常。

你现在可能意识到,一旦SYSCALL完成执行,#DB就会触发,就像我们单步执行任何其他分支指令一样。因此,如果LSTAR目标看起来像下面的代码序列:

1
2
3
0x40000: SWAPGS
0x40001: MOV GS:[0x8], RSP
0x40002: MOV RSP, GS:[0x10]

#DB处理程序中断堆栈将包含0x40000,因为这是syscall操作分支目标,尚未执行。

正如你可能已经意识到的,Patchguard可以通过在其中断处理程序中检查生成#DB的IP来间接发现LSTAR MSR的真实内容。这是一种发现恶意虚拟机是否在RDMSR/WRMSR上退出并给操作系统预期值的方法。

接下来是我个人最喜欢的KiErrataSkx55Present。它是对CVE-2018-8897的回顾,并在该漏洞被缓解后不久添加到Patchguard中。为了深入了解此检测的工作原理,你应该阅读POP SS/MOV SS漏洞白皮书。

如果你读过该论文,那么这几乎不言自明。因此,给定上面的SYSCALL处理程序示例,此#DB在其中断堆栈上也有0x40000。

既然客户机代码现在可以拥有超越RDMSR/WRMSR的智慧,年轻的Hypervisor在这种情况下该怎么做?很简单,设置我们的异常位图,以便在#DB异常时退出,并检查客户状态IP以处理上述两种可能的指令边界#DB,如果不匹配,则通过向量事件注入将其反射回客户机。检查退出资格而不是仅仅检查客户状态中设置的TF是明智的。

让我告诉你一个流行的反病毒Hypervisor未能做到这一点的故事,因此当它将#DB注入回客户机到其秘密syscall处理程序的RIP时,KiDebugTraps缓解措施并不知情,这使得你的系统再次容易受到CVE-2018-8897的攻击。

最后,锦上添花的是,一个坚实的检查,只有在你在#DB异常上退出时才会炸毁你的Hypervisor,因为,你 kinda gotta amiright?进入KiErrata361Present。

这里有点复杂,让我解释一下。在正常情况下,通过POPF变体加载带有TF的RFLAGS,然后加载SS,将在SS加载后的指令边界之后看到单步。这对于因命中武装调试寄存器而触发的#DB也是如此,当被加载SS暂时阻塞时。在上面的情况下,INTn(也称为软件中断)或专用的INT3操作码(也称为软件异常)不关心先前通过TF挂起的#DB,无论如何它都会被丢弃。

这与ICEBP的自然行为相同,尽管未记录,但你在Intel手册中看到的是特权软件异常。在这种情况下,#DB不会有DR6.BS设置,即使它挂起,由于这些操作码本机操作的性质,它被丢弃。ICEBP实际上在引发#DB VMEXIT时带有此警告。在正常的架构情况下,BS位将在VMCS中的挂起调试异常字段中设置,因为这是真实状态,但是当退出由特权软件异常引起时,该位被清除。

因此,VMCS的状态不可自然恢复,并将导致VMRESUME失败,导致大多数Hypervisor当场拉出水样日志。架构要求,如果虚拟CPU处于中断阴影中,使得通过MOV SS/POP SS启用阻塞并且设置了TF位,则必须存在基于BS的挂起#DB,因为没有其他方法可以获取此机器状态。修复此问题也相对简单:在符合条件的退出时检查特权软件异常,如果指示通过MOV SS阻塞以及TF==1,则确保在挂起调试异常中设置BS。

KiErrata361Present的想法实际上取自CVE-2018-1087漏洞,在特权软件异常确实是ICEBP公开已知之前,并在该漏洞在KVM中缓解后不久出现在Patchguard中。Intel SDM此后已更新以指示特权软件异常实际上是什么,但仍然遗漏了此边缘情况。

如果这不太无聊,请继续阅读第二部分,我们讨论另一个Patchguard检测,并使用一些批判性思维来提出我们自己的巧妙技巧!

版权所有 © 2020 Digiprove 保留所有权利 这里的原始内容根据这些许可条款发布:X 许可证类型:只读 许可证摘要:你可以在发布原始内容的上下文中阅读它(在此网址)。未经作者书面同意,不允许其他复制或使用。

作者

Nick Peterson

查看所有帖子

10 thoughts on “Patchguard: Detection of Hypervisor Based Introspection [P1]”

Pingback: Patchguard: Detection of Hypervisor Based Introspection [P2] - Reverse Engineering

fucklg says: April 27, 2020 at 05:12 我有一个问题。我的问题可能有点天真,但我有点困惑。既然是单步异常,那么它在边界处中断。它如何继续执行以下指令?不执行以下指令,它无法找到你的Hypervisor

登录回复

Nick Peterson says: April 28, 2020 at 17:48 好问题,可能我让它难以理解。 它不继续执行指令。单步执行syscall与单步执行call指令没有什么不同。中断堆栈中显示的IP是分支目标的IP,因为单步#DB在指令退休后触发,并且已经计算了新的IP。 对于syscall来说没有什么不同,并且是暴露syscall将分支到的位置的第二种方式,除了读取MSR值。 这有意义吗?

登录回复

Pingback: 4月28日每日安全热点 - iOS上默认的Mail应用程序MobileMail / Maild 0-click漏洞分析 - 安全客,安全资讯平台

Pingback: 4月27日每日安全热点 - iPhone面临通过电子邮件应用程序被黑客入侵的风险 - 安全客,安全资讯平台

Pingback: 4月28日每日安全热点 – iOS上默认的Mail应用程序MobileMail / Maild 0-click漏洞分析-中国宏阔黑客联盟|白帽黑客|网络渗透技术|网站安全|移动安全|通信安全

Pingback: canadianpharmacyusa24h

Pingback: 4月27日每日安全热点 – iPhone面临通过电子邮件应用程序被黑客入侵的风险 | ZONE.CI 全球网

Pingback: 4月28日每日安全热点 – iOS上默认的Mail应用程序MobileMail / Maild 0-click漏洞分析 | ZONE.CI 全球网

Pingback: Homepage

留下回复 取消回复 你必须登录才能发表评论。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计