使用LiveCloudKd进行安全内核研究
假设您想要研究安全内核。您听说过虚拟机监控程序(hypervisors)和VTL1,并希望亲身体验,而静态分析往往不够充分。您需要一个调试器。
但您立即遇到了一个问题:无法调试安全内核、安全进程或任何在VTL1中运行的内容。当然,您可以调试虚拟机监控程序,并通过痛苦地分析物理内存、记忆大量偏移量和字节模式来找到安全内核并从此处着手。这正是Francisco Falcon(当时来自Quarkslab)几个月前调试隔离用户模式(IUM)进程(也称为安全进程)时所做的。他在这里发表了他的工作。他的过程令人印象深刻,但难以复制,因为虚拟机监控程序二进制文件不附带公共符号,且偏移量和结构在构建之间会发生变化,因此您必须为每个单独的构建找到正确的版本。
如果您想调试虚拟机监控程序本身,除了处理这个痛苦的过程外,没有太多选择。但对于调试安全内核(以及通过它调试IUM进程),您可以尝试使用LiveCloudKd。
LiveCloudKd最初由Matt Suiche开发,自2020年起由Gerhart维护,它允许您将实时调试器附加到虚拟机并调试安全内核。存储库中确实有设置调试器的说明,但它们对我并不完全有效,因此我将在此记录我的过程,希望能帮助他人,并展示将内核调试器附加到安全内核的一些用途。
初始设置
下载最新版本的LiveCloudKd。或者,如果您希望能够附加完整调试器(并可能单步执行VTL1中的代码),请下载LiveCloudKd调试器。
在我的设置中,我使用了LiveCloudKd调试器,构建版本v1.0.22021109。您可以在这里找到它。
选择虚拟机设置
设置您想要调试的虚拟机。虚拟机需要支持基于虚拟化的安全性(否则这一切的意义何在?),因此必须至少安装Windows 10。我使用Hyper-V作为我的虚拟机基础设施,并创建了一个运行Windows 11的虚拟机。
在文档中,Gerhart推荐嵌套虚拟机设置:一个虚拟机(安装有Server 2019)作为主机,在其内部创建另一个作为客户机的虚拟机。您在主机虚拟机中设置一切,并调试客户机虚拟机。这种设置有效,但我发现使用嵌套虚拟机不方便,因此我在我的主机(64位Windows 11 23H2)上设置了一切,并调试了一个虚拟机。
设置主机机器
设置主机机器(无论是您真实的主机还是主机虚拟机):
- 在主机机器上安装最新的Windows SDK。您可以在这里下载最新版本,或者如果您愿意,可以使用Insider Preview SDK。
- 在主机机器上安装Visual Studio 2022运行时库。您可以在这里下载它们。
- 解压您在步骤1中下载的LiveCloudKd,并将其内容复制到WinDbg目录(c:\Program Files (x86)\Windows Kits\10\Debuggers\x64)。
- 如果您更喜欢使用新的和改进的WinDbg,请将WinDbgX及其所有依赖项复制到一个新文件夹,并将所有LiveCloudKd二进制文件复制到同一文件夹。
在我尝试运行LiveCloudKd时,有些仅适用于旧版WinDbg,有些仅适用于新版WinDbg。我鼓励您尝试两者,看看哪个有效。
在提升权限的命令行中,导航到您放置LiveCloudKd的目录,并使用以下命令安装ExdiKdSample:
|
|
(如果您使用的是主存储库中的LiveCloudKd,而不是调试器,那么您需要安装的DLL名为HvmmEXDi.dll)
配置您的符号路径(c:\symbols,或您选择的任何其他目录,必须存在):
|
|
设置客户机机器
不要为客户系统启用嵌套虚拟化。默认情况下应禁用,但如果您需要禁用它,可以按照本指南为Hyper-V机器禁用它(您需要在主机上执行此操作,而不是在客户机内部)。
在客户机中启用基于虚拟化的安全性。您可以通过转到安全设置 -> 设备安全 -> 核心隔离并启用内存完整性来启用它。
或者,如果您更喜欢通过注册表或组策略启用它,可以按照这些说明操作。
您不需要在客户机中禁用安全启动即可使用LiveCloudKd进行调试。如果您仍然想禁用安全启动,您需要将此注册表值设置为零,以允许基于虚拟化的安全性在没有安全启动的情况下运行:
|
|
现在,在提升权限的命令行中,导航到您设置LiveCloudKd的目录并运行它。选择您想要调试的索引或虚拟机,然后选择“Start EXDi plugin”(或者如果您像我一样使用调试器构建,选择“Live Kernel Debugger”)。如果幸运的话,您现在有一个内核调试器附加到客户机的安全内核。如果这没有奏效,您可能遇到了与我相同的问题。尽管我的符号路径配置正确,LiveCloudKd忽略了它,未能找到所需的符号。因此,我必须自己设置它们。
符号
LiveCloudKd需要客户机中的两个模块的符号:
- Ntoskrnl.exe
- Securekernel.exe
因此,如果您遇到了与我相同的问题,请登录到您的客户机,并从c:\Windows\System32获取这两个二进制文件。将它们复制到您的主机机器。然后,使用symchk.exe(您可以在旧版WinDbg的同一目录中找到它)下载它们的符号:
|
|
输出将显示您下载的两个pdb文件的路径。将它们都复制到与LiveCloudKd相同的文件夹。您还需要将ntoskrnl.pdb(或ntkrnlmp.pdb)重命名为nt.pdb,因为这是LiveCloudKd使用的文件名。无需将securekernel.pdb重命名为任何其他名称。
现在,尝试再次运行LiveCloudKd。如果有效,完美!如果无效,请跟随我进入下一阶段。
多阶段解决方案
我遇到的另一个问题是,有时LiveCloudKd能够定位ntoskrnl.exe和securekernel.exe,但在其初始化的另一步骤中失败。我实际上没有找到解决方案,只是一种绕过它的方法。如果您怀疑在您的情况下发生了这种情况,请尝试在详细模式下运行LiveCloudKd:
|
|
希望您会得到类似这样的输出:
您的输出可能看起来不同,有更多错误或在不同的阶段失败。但如果LiveCloudKd成功打印了NT内核和安全内核的基地址,您就可以继续了。该过程并不总是自行退出,因此您现在可以中断它。
在注册表中,将此注册表值设置为您选择调试的虚拟机的索引(与您在LiveCloudKd交互输入中选择的相同ID):
|
|
然后,启动实时调试器:
|
|
或者,如果您更喜欢活动调试器,可以(可能)设置断点并逐步执行代码,运行:
|
|
(如果您使用新的调试器,请将windbg.exe替换为WinDbgX。如果无效,请尝试旧版调试器,反之亦然)
然后……成功!
这次只有旧版WinDbg有效,但胜利就是胜利。
现在,从先前的输出中获取securekernel.exe的地址,并在调试器中运行:
|
|
现在您拥有了所有加载的内核模块以及安全内核的地址,所有这些都可以通过调试器访问。但调试器不知道VTL1中加载的其他模块。让我们去找它们。
VTL1加载的模块
Securekernel.exe是内核的VTL1版本。就像常规内核一样,安全内核负责跟踪其地址空间中加载的模块并加载新模块。它将有关加载模块的信息保存在一个列表中,该列表起始于securekernel!SkLoadedModules,我们可以使用DX读取:
|
|
幸运的是,此列表中的条目使用与正常内核管理其模块相同的数据结构:KLDR_DATA_TABLE_ENTRY。因此我们可以轻松解析列表:
|
|
并找到所有VTL1内核模块的名称和地址:
|
|
当然,我们可以用我们的新调试器做更复杂的事情。比如启用安全内核调试、修补变量和函数以允许我们在VTL1中运行未签名的代码进行测试,或者做许多其他事情。但这些需要更多的工作和努力,因此我将这篇文章作为入门篇,并将所有其他想法留给未来的文章。