-
-
Hypervisor From Scratch – 第 5 部分:设置 VMCS 和运行来宾代码
-
发表于: 2024-3-31 13:22 9122
-
您好,欢迎来到“ Hypervisor From Scratch ”教程系列的第五部分。今天我们将花时间研究虚拟机控制结构(VMCS)的不同部分,实现额外的VMX指令,创建恢复点,设置不同的VMCS控制结构,最后,我们执行VMLAUNCH,进入硬件虚拟化世界!
本主题的大部分内容源自英特尔 64 和 IA-32 架构软件开发人员手册 (英特尔 SDM) 合并卷 3 中的第 24 章 –(虚拟机控制结构)和第 26 章–(虚拟机条目)。
这部分的灵感来自于《Hypervisor For Beginner》。
在阅读本部分的其余部分之前,请务必阅读前面的部分,因为它为您提供了彻底理解本主题的其余部分所需的知识。
在 第3部分 中,我们实现了 VMXOFF 函数,现在让我们实现其他VMX指令函数。 我还在调用 VMXON 和 VMPTRLD 函数方面进行了一些更改,以使其更加模块化。
VMPTRST 指令将当前VMCS指针存储到指定的内存地址中。 该指令的操作数始终是 64 位,并且始终是内存中的一个位置。
以下函数是VMPTRST的实现 :
该指令适用于 VMCS,其中 VMCS 区域驻留在指令操作数中包含的物理地址。 该指令确保该 VMCS 的 VMCS 数据(其中一些数据当前可能保存在处理器上)被复制到内存中的 VMCS 区域。 它还会初始化 VMCS 区域的某些部分(例如,它将该 VMCS 的启动状态设置为清除)。
该指令将当前 VMCS 指针标记为有效,并使用指令操作数中的物理地址加载它。 如果其操作数未正确对齐、设置不支持的物理地址位或等于 VMXON 指针,则指令将失败。 此外,如果操作数引用的内存中的 32 位与处理器支持的 VMCS 修订标识符不匹配,则该指令会失败。
为了实现 VMRESUME ,您需要了解一些 VMCS 字段,因此 VMRESUME 指令的解释等我们在实现VMLAUNCH 后。 (本主题稍后)
正如我之前告诉你的,我们需要一个结构来分别保存每个核心中虚拟机的状态。 我们最新版本的虚拟机管理程序中使用了以下结构。 我们将在本主题的其余部分中描述每个字段。
请注意,这不是最终的 VIRTUAL_MACHINE_STATE 结构; 我们将来会加强它。
在这一部分中,我们只是尝试增强我们的虚拟机管理程序驱动程序。 在以后的部分中,我们将添加一些与驱动程序的用户模式交互,但现在,让我们从修改 DriverEntry 开始,因为它是加载驱动程序时执行的第一个函数。
除了第 2 部分 的所有准备工作之外,我们还添加了以下几行来使用 第 4 部分 (EPT) 结构:
我们还添加了一个名为“ g_VirtualGuestMemoryAddress ”的全局变量的导出,该变量保存guest代码开始的地址。
现在让我们用 \xf4 指令的十六进制表示 填充分配的页面,它是HLT 。 我选择 HLT 是 因为,通过一些特殊配置(如下所述),它将导致 VM-exit并将代码返回到主机处理程序; 因此,这将是这部分的一个很好的例子。
之后,我们开始创建一个名为LaunchVm
的函数 ,它负责在特定核心上运行我们的虚拟机。 在这一部分中,我们将仅在 第 0 个 逻辑处理器中测试我们的虚拟机管理程序。 在未来的部分中,我们将扩展我们的虚拟机管理程序以虚拟化整个系统。
请记住,每个逻辑核心都有自己的 VMCS,如果我们希望guest代码在其他逻辑处理器中运行,我们应该单独配置每个逻辑处理器。
要在某个逻辑核心中运行代码,我们应该使用 Windows KeSetSystemAffinityThread函数设置亲和性,并选择特定核心的VIRTUAL_MACHINE_STATE,因为每个核心都有自己独立的 VMXON 和 VMCS 区域。
以下代码描述了如何在不同的逻辑核心中运行我们的代码。
现在我们可以指定核心编号并在目标核心中执行代码,现在应该分配一个特定的 堆栈 ,以便每当发生 VM-exit时,我们可以保存寄存器并在 vmx-root 模式下调用其他主机函数。
快速提醒一下,每当发生 vm-exit 时,就会在 vmx-root 模式下调用主机处理程序。 当我们运行 VMRESUME 指令时,处理器切换到VMX non-root; 因此,每个内核模式驱动程序和用户模式应用程序都在 VMX non-root 模式下运行。 只有驱动程序中负责处理主机的部分在 VMX root-mode下执行。
这里我们需要一个用于主机例程的堆栈。 我们有两个选择,第一个选项是使用当前的 RSP ,第二个选项是使用单独的堆栈。 我们为堆栈使用了单独的位置,而不是使用驱动程序的当前 RSP ,但您也可以使用当前堆栈 (RSP)。
以下几行是为了分配和清零 VM-exit处理程序的堆栈而编写的。
与上面相同,我们将为 MSR Bitmap 分配一个页面并将其添加到 GuestState 。 我稍后将在本主题中描述它们。
下一步是清除 VMCS 状态并将其加载为特定处理器(在我们的示例中为第 0 个逻辑处理器)中的当前 VMCS。
ClearVmcsState
和 LoadVmcs
函数的使用如上所述:
现在是时候设置 VMCS 了。 我们将在本主题后面详细讨论如何配置 VMCS,但现在假设有一个名为 SetupVmcs
的函数,它配置 VMCS 结构。
最后一步是执行 VMLAUNCH 指令。 然而我们不应该忘记保存堆栈的当前状态( RSP 和 RBP 寄存器)。 这是因为执行 VMLAUNCH 指令后, RIP 寄存器更改为 GUEST_RIP ; 因此,我们需要保存之前的系统状态,以便在从VM函数返回后可以返回到正常的系统例程。 如果我们给驱动程序留下错误的 RSP 和 RBP 寄存器,我们将看到 BSOD。 为此目的, 使用AsmSaveStateForVmxoff
函数。
为了 AsmSaveStateForVmxoff
,我们声明两个名为 g_StackPointerForReturning 和 g_BasePointerForReturning 的全局变量。 无需保存 RIP 寄存器,因为堆栈的返回地址始终可用。 只需在汇编文件中 EXTERN 即可:
AsmSaveStateForVmxoff
的实现:
我们的虚拟机管理程序的最后一步是返回到之前的系统状态并关闭虚拟机管理程序。
我们之前保存了系统状态。 现在,我们可以恢复它( RSP 和 RBP 寄存器)并清除堆栈位置。
在此之前, 执行VMXOFF 指令来关闭管理程序。
看看下面的代码。
最后,我们需要精确地清除堆栈。 之前我们称之为 LaunchVm
函数并最终形成一个新的 RIP 。 为了正常继续执行,我们需要清除堆栈并返回到调用 LaunchVm
函数的位置。 因此,在上面汇编代码的最后一部分,也就是“返回部分”,我用IDA Pro来看了反汇编 LaunchVm
,所以我们可以看到这个函数如何清除堆栈,并且我们执行相同的操作,以便我们可以优雅地返回之前的系统状态。 因此,“返回部分”是从LaunchVm
IDA Pro 的反汇编中复制的。
是时候谈谈 VMLAUNCH 指令了。
看看下面的代码。
__vmx_vmlaunch()
是VMLAUNCH 指令的内在函数,而 __vmx_vmread
是 VMREAD 指令的内在函数。
正如注释所描述的,如果 VMLAUNCH 成功,我们将永远不会执行其他行。 如果VMCS的状态出现错误(这是一个常见问题),我们必须运行 VMREAD 并从 VMCS 的 VM_INSTRUCTION_ERROR 字段读取错误代码。 出现错误时还需要运行 VMXOFF 来关闭虚拟机管理程序,最后我们可以打印错误代码。
DbgBreakPoint只是一个调试断点(int 3),只有当我们使用远程内核 WinDbg 调试器时它才有用。很明显,你无法在本地调试系统中测试它,因为只要没有调试器捕获它,在内核中执行int 3就会冻结你的系统,因此强烈建议创建一个远程内核调试机器并测试您的代码可能存在的错误。
您还可以使用VMware Workstation的嵌套虚拟化来创建远程内核调试连接。 Intel没有“嵌套虚拟化”这样的东西,但提供了一些硬件设施,以便厂商可以自己支持和实现嵌套虚拟化。 例如,您可以在具有嵌套虚拟化支持的 VMware Workstation 上测试您的驱动程序(我还在第一部分中解释了如何在 VMware 上调试虚拟机管理程序驱动程序)。但是,支持 Hyper-V 嵌套虚拟化在实现虚拟机管理程序时需要考虑额外的事情,因此我们无法在 Hyper-V 嵌套虚拟化上测试我们的驱动程序,至少对于这一部分来说是这样。 我将在第 8 部分中解释 Hyper-V 支持。
这些驱动程序在物理机和 VMware Workstation 的嵌套虚拟化上进行了测试。
现在是时候在深入研究 VMCS 的配置之前阅读一些理论了。
让我们讨论一下 VMCS 中管理guest行为的不同控件。 我们将在本部分中使用其中一些位,并且将在以后的部分中使用其中一些位。 所以,不用担心。 只需看一下这些位的描述并了解它们即可
为了控制我们的guest功能,我们必须在 VMCS 中设置一些字段。 下表表示Primary Processor-Based VM-Execution Controls 和the Secondary Processor-Based VM-Execution Controls。
我们这样定义上表:
在 VMX 的早期版本中,没有类似Secondary Processor-Based VM-Execution Controls的功能。 现在,如果我们想使用辅助表,我们必须设置第一个表的第31位; 否则,它就像带有零的辅助表字段。
上表的定义是这样的(我们忽略一些位,如果你想在虚拟机管理程序中使用它们,你可以定义它们):
VM-entry controls构成一个 32 位向量,用于管理 VM entries的基本操作
VM-exit controls构成一个 32 位向量,用于管理 VM-exit的基本操作。
pin-based VM-execution controls构成一个 32 位向量,用于管理异步事件(例如中断)的处理。 我们将在以后的部分中使用它,但现在,让我们在虚拟机管理程序中定义它。
现在我们已经了解了一些 VMCS 字段和控件的基本概念,是时候完全配置 VMCS 结构以使我们的虚拟化guest做好准备了。
为了配置我们的Guest-State和Host-State,我们需要了解当前系统状态的详细信息,例如全局描述符表地址(GDT)、中断描述符表(IDT)地址并读取所有段寄存器。.
这些函数描述了如何收集所有这些寄存器和段。
GDT Base:
CS段寄存器:
DS段寄存器:
ES段寄存器:
SS段寄存器:
FS段寄存器:
GS段寄存器:
LDT:
TR(任务寄存器):
中断描述符表:
GDT Limit:
IDT Limit:
RFLAGS:
让我们言归正传吧(我们还有很长的路要走)。
本节首先定义一个名为 SetupVmcs
的函数.
该函数负责配置与 VMCS 相关的所有选项,当然还有 Guest & Host 状态。
配置和修改 VMCS 是通过使用名为“ VMWRITE”的特殊指令来完成的 。
VMWRITE 将主源操作数(寄存器或内存)的内容写入 VMCS 中的指定字段。 在VMX-root 操作中,指令写入当前VMCS。 如果在VMX non-root 操作中执行,则该指令写入由当前VMCS中的VMCS链接指针字段引用的VMCS。
VMCS 字段由寄存器辅助源操作数中包含的 VMCS-field encoding指定。
以下枚举包含VMWRITE和VMREAD指令所需的大部分 VMCS 字段。 (较新的处理器添加了较新的字段。)
好的,让我们继续我们的配置。
下一步是配置 host段寄存器。
请记住,以“ HOST_ ”开头的字段与虚拟机管理程序在发生 VM-exit时设置的状态相关,而以“GUEST_”开头的与执行 VMLAUNCH 时虚拟机管理程序为 guest 设置的状态相关
& 0xF8
的目的是Intel提到必须清除三个较低有效位; 否则,会导致错误,因为 VMLAUNCH 执行 时会出现无效主机状态 错误。
接下来,我们设置 VMCS_LINK_POINTER
,应该是“0xffffffffffffffff”。 因为我们没有额外的 VMCS。 该字段主要用于想要实现嵌套虚拟化行为的虚拟机管理程序(例如 VMware 嵌套虚拟化或 KVM 的 nVMX)。
本主题的其余部分旨在虚拟化计算机的当前状态,因此guest和主机配置必须相同。
让我们配置GUEST_IA32_DEBUGCTL。该字段的工作方式与物理机中的IA32_DEBUGCTL MSR相同,如果我们想为每个客户机使用单独的IA32_DEBUGCTL ,我们可以使用它。它提供位字段控制来启用调试跟踪中断、调试跟踪存储、跟踪消息启用、分支上的单步执行、最后分支记录记录以及 LBR 堆栈的控制冻结。
我们不在虚拟机管理程序中使用它,但我们应该将其配置为当前计算机的 MSR_IA32_DEBUGCTL 。 我们用 __readmsr()
读取此 MSR (RDMSR) 并将物理机的值放入guest的内部 GUEST_IA32_DEBUGCTL
.
请注意,我们在其上置零的值可以被忽略; 如果你不修改它们,就好像你在它们上加了零。
例如,在当前状态下,配置 TSC 对于我们的虚拟机管理程序并不重要,因此我们将其设置为 0。
这次,我们将根据主机的 GDT 基地址配置段寄存器(当 VM-exit时)。
GetGdtBase
上面在为我们的 VMCS 收集信息的过程中定义了。
FillGuestSelectorData
负责设置 VMCS 的 GUEST 选择器、属性、限制和基础。 其实现如下:
GetSegmentDescriptor 的函数体 :
另一个名为 IA32_KERNEL_GS_BASE 的 MSR 用于设置内核 GS 基址。 每当执行像 SYSCALL 这样的指令,并且处理器进入环 0 时,我们需要更改当前的 GS 寄存器,这可以使用 SWAPGS 指令来完成。 该指令将 IA32_KERNEL_GS_BASE 的内容复制到 IA32_GS_BASE 中,现在当内核想要重新进入用户模式时使用它。
另一方面,MSR_FS_BASE 没有内核基础,因为它在 32 位模式下使用,而我们有 64 位(长模式)内核。
与上面的MSR一样,我们将根据当前系统的MSR配置IA32_GS_BASE和IA32_FS_BASE MSR。
GUEST_INTERRUPTIBILITY_INFO 和 GUEST_ACTIVITY_STATE 设置为零(我们将在以后的部分中描述它们)。
现在我们到达了VMCS的一个重要部分,它是CPU_BASED_VM_EXEC_CONTROL和 SECONDARY_VM_EXEC_CONTROL控件的配置 。
这些字段启用和禁用客户机的一些基本功能,例如,我们可以将 VMCS 配置为在检测到(在客户机中)执行HLT指令时导致 VM-exit 。 您可以阅读本主题的虚拟机执行控制部分中每个位的描述 。
如您所见,我们设置了 CPU_BASED_HLT_EXITING,这将导致 HLT 上的 VM 退出,并使用 CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 位激活辅助控制。
在辅助控件中,我们使用了CPU_BASED_CTL2_RDTSCP,现在注释CPU_BASED_CTL2_ENABLE_EPT,因为我们不需要在这部分处理EPT。 在第七部分中,我详细描述了EPT。
PIN_BASED_VM_EXEC_CONTROL、VM_EXIT_CONTROLS 和 VM_ENTRY_CONTROLS 的描述可在上面找到。 这部分我们没有对这些控件进行任何特殊的配置; 因此,让我们把它们归零。
另外, AdjustControls
是一个用于配置这些字段的 0 设置和 1 设置的函数(我们将在以后的部分中描述它们),但现在; 它的定义如下:
下一步是为guest和主机设置控制寄存器和调试寄存器 (DR7)。 我们使用内在函数将它们设置为与当前机器状态相同的值。
下一部分是为我们的guest设置 IDT 和 GDT 的 Base 和 Limit 。 一般来说, 为guest和主机使用相同的 IDT(和 GDT)并不是一个好主意 ,但为了保持我们的虚拟机管理程序简单,我们将它们配置为相同的值。
接下来,设置 RFLAGS。
如果您想在guest中使用 SYSENTER,您应该配置以下 MSR。 在 x64 Windows 中设置这些值并不重要,因为 Windows 在 x64 版本的 Windows 中不支持 SYSENTER; 相反,它使用 SYSCALL。
相同的指令也适用于 32 位进程。 在32位进程中,Windows首先将执行模式更改为长模式(使用 天堂之门技术 ),然后执行SYSCALL指令。
不要忘记为 VMCS 中的主机 配置HOST_FS_BASE 、 HOST_GS_BASE 、 HOST_GDTR_BASE 、 HOST_IDTR_BASE 、 HOST_TR_BASE 。
下一个重要部分是在执行 VMLAUNCH 时设置 guest 虚拟机的 RIP 和 RSP 寄存器。 当虚拟机退出时,它从您在本部分中配置的 RIP 以及主机的 RIP 和 RSP 开始。 很明显,主机 RIP 应该指向一个负责根据 VM 退出代码管理 VMX 事件的函数,以及是否决定执行 VMRESUME 或使用 VMXOFF 关闭虚拟机管理程序。
HOST_RSP指向我们之前分配的VmmStack,HOST_RIP指向AsmVmexitHandler(下面描述的汇编编写的函数)。GUEST_RIP指向g_VirtualGuestMemoryAddress(我们在 EPT 初始化期间配置的全局变量),而GUEST_RSP指向同一地址 ( g_VirtualGuestMemoryAddress ),因为我们没有放置任何使用堆栈的指令,因此对于实际示例,它应该指向一个不同的可写地址。
完毕!我们的 VMCS 即将准备就绪。
不幸的是,检查 VMCS 布局并不像其他部分那么直接。 我们必须控制英特尔 64 和 IA-32 架构软件开发人员手册中的[第 26 章]VM 条目中描述的所有检查表,包括以下部分:
此过程中最困难的部分是当我们不知道 VMCS 布局的不正确部分时,或者另一方面,当您错过最终导致失败的某些内容时。
这是因为 Intel 只提供了一个错误号,而没有提供有关 VMCS 布局中具体错误的任何进一步详细信息。
错误如下所示。
为了解决这个问题,我创建了一个名为VmcsAuditor的用户模式应用程序。正如它的名字所描述的,如果你有任何错误并且不知道如何解决问题,它可以是一个选择。
请记住, VmcsAuditor 是一个基于 Bochs 模拟器对 VMX 支持的工具,因此所有检查都来自 Bochs,并且它不是一个解决所有问题的 100% 可靠工具,因为我们不知道处理器内部到底发生了什么。 尽管如此,它仍然很方便并且节省时间。
源代码和可执行文件可在 GitHub 上获取:
[ https://github.com/SinaKarvandi/VMCS-Auditor ]
详细说明请参见 此处 。
作为更好的选择,您可以使用 Satoshi Tanda 的 **[代码 ](https://github.com/SinaKarvandi/Hypervisor-From-Scratch/tree/master/Part 5 - Setting up VMCS %26 Running Guest Code/VMCS-Checks)**来检查guest状态。
当我们的guest软件退出并将句柄返回给主机时,可能会发生以下虚拟机退出原因。
VMX-exit 处理程序应该是一个汇编函数,因为调用编译函数需要一些准备工作和一些寄存器修改。 VM-exit处理程序中必要的事情是保存寄存器的状态,以便我们稍后可以继续guest。
我创建了一个用于保存和恢复寄存器的示例函数。 在此函数中,我们调用另一个 C 函数来扩展 vm-exit 处理程序。
主要的 VM-exit处理程序是一个 switch-case 函数,对 VMCS VM_EXIT_REASON 和 EXIT_QUALIFICATION 具有不同的决策。
在这一部分中,我们只是通过EXIT_REASON_HLT执行操作,然后打印结果并正常恢复来宾状态。
从下面的代码中,您可以看到什么事件导致VM退出。 请记住,如果 VMCS 的控制执行字段(如上所述)配置了某些原因,则仅会导致 VM-exit。 例如,如果基于主处理器的 VM 执行控制的第7位允许,则来宾中HLT指令的执行将导致 VM 退出。
如果发生VM退出(例如,Guest执行了 CPUID 指令),Guest RIP 保持不变,并且由VMM决定是否更改Guest的 RIP ,因此如果我们没有某种功能来管理这种情况,然后处理器执行 CPUID 指令的无限循环,因为我们没有增加 RIP 。
为了解决这个问题,我们必须读取一个名为 VM_EXIT_INSTRUCTION_LEN 的 VMCS 字段,该字段存储导致 VM-exit的指令的长度。
首先,我们必须从GUEST_RIP读取访客当前的RIP。其次,使用VMREAD读取VM_EXIT_INSTRUCTION_LEN ,第三,读取客户机RIP的指令长度。现在,guest将从下一条指令继续执行,我们就可以开始了。
下面的函数就是为了这个目的。
现在我们已经处理了虚拟机退出,是时候继续guest了。 指令继续执行 我们可以使用VMRESUME 。
VMRESUME 类似于 VMLAUNCH ,但它用于恢复guest系统。
为了比较这些指令,
所以很明显,如果我们之前执行了VMLAUNCH指令,我们就不能再使用它来恢复客户代码,在这种情况下,需要使用VMRESUME 。
以下代码是VMRESUME 的实现。
好了,我们已经完成了配置,现在是时候运行我们的驱动程序了。 与往常一样,我们应该禁用驱动程序签名强制并运行我们的驱动程序。
从上图可以看出(在启动VM区域),首先,我们将当前逻辑处理器设置为0。接下来,我们使用VMCLEAR指令清除VMCS状态 , 设置VMCS布局并执行 VMLAUNCH 指令。
现在,我们的来宾代码已执行,并且我们将 VMCS 配置为在执行HLT **(CPU_BASED_HLT_EXITING)**指令时导致 VM 退出。
运行 guest 虚拟机后,将调用 VM 退出处理程序,然后调用主 VM 退出处理程序,并且由于 VMCS 退出原因为0xc (EXIT_REASON_HLT) ,因此我们成功检测到guest 虚拟机中HLT的执行。
之后,我们的机器状态保存机制被执行,我们使用 VMXOFF 指令成功关闭虚拟机管理程序,并以成功的 (RAX = 1) 状态返回到第一个调用者。
就是这样! 这不是很容易吗?
在这一部分中,我们熟悉了配置虚拟机控制结构并最终运行了我们的guest代码。 未来的部分将是对此配置的增强,例如进入 保护模式、 中断注入 、 页面修改日志记录、 虚拟化当前机器 等等。 如果您有任何疑问或问题,可以使用下面的评论部分。
[1] 第 3C 卷 - 第 24 章 –(虚拟机控制结构 ( https://software.intel.com/en-us/articles/intel-sdm )
[2] 第 3C 卷 - 第 26 章 –(虚拟机条目)( https://software.intel.com/en-us/articles/intel-sdm )
[3] 分段( https://wiki.osdev.org/Segmentation )
[4] x86 内存分段 ( https://en.wikipedia.org/wiki/X86_memory_segmentation )
[5] VmcsAuditor – 基于 Bochs 的虚拟机管理程序布局检查器 ( https://rayanfam.com/topics/vmcsauditor-a-bochs-based-hypervisor-layout-checker/ )
[6] Rohaaan/Hypervisor 初学者 ( https://github.com/rohaaan/hypervisor-for-beginners )
[7] SWAPGS — 交换 GS 基址寄存器 ( https://www.felixcloutier.com/x86/SWAPGS.html )
[8] 敲开天堂之门 - 动态处理器模式切换 ( http://rce.co/knockin-on-heavens-gate-dynamic-processor-mode-switching/ )
- 五、设置VMCS和运行guest代码
- 5.1.介绍
- 5.2.概述
- 5.3.VMX指令
- 5.3.1.VMPTRST
- 5.3.2.VMCLEAR
- 5.3.3.VMPTRLD
- 5.4.增强VM状态结构
- 5.5.准备启动VM
- 5.6.保存返回点
- 5.7.返回到之前的状态
- 5.8.VMLAUNCH指令
- 5.9.VM Controls
- 5.9.1.VM-Execution Controls
- 5.9.2.VM-entry Control Bits
- 5.9.3.VM-exit Control Bits
- 5.9.4.PIN-Based Execution Control
- 5.10.配置VMCS
- 5.10.1.收集VMCS的计算机状态
- 5.10.2.设置VMCS
- 5.10.3.检查VMCS布局
- 5.11.VM退出处理程序
- 5.11.1.继续执行下一条指令
- 5.12.VMRESUME指令
- 5.13.让我们测试一下
- 5.14.结论
- 5.15.参考
UINT64
VmptrstInstruction()
{
PHYSICAL_ADDRESS vmcspa;
vmcspa.QuadPart = 0;
__vmx_vmptrst((unsigned
__int64
*)&vmcspa);
DbgPrint(
"[*] VMPTRST %llx\n"
, vmcspa);
return
0;
}
UINT64
VmptrstInstruction()
{
PHYSICAL_ADDRESS vmcspa;
vmcspa.QuadPart = 0;
__vmx_vmptrst((unsigned
__int64
*)&vmcspa);
DbgPrint(
"[*] VMPTRST %llx\n"
, vmcspa);
return
0;
}
BOOLEAN
ClearVmcsState(VIRTUAL_MACHINE_STATE * GuestState)
{
// Clear the state of the VMCS to inactive
int
status = __vmx_vmclear(&GuestState->VmcsRegion);
DbgPrint(
"[*] VMCS VMCLAEAR Status is : %d\n"
, status);
if
(status)
{
// Otherwise, terminate the VMX
DbgPrint(
"[*] VMCS failed to clear with status %d\n"
, status);
__vmx_off();
return
FALSE;
}
return
TRUE;
}
BOOLEAN
ClearVmcsState(VIRTUAL_MACHINE_STATE * GuestState)
{
// Clear the state of the VMCS to inactive
int
status = __vmx_vmclear(&GuestState->VmcsRegion);
DbgPrint(
"[*] VMCS VMCLAEAR Status is : %d\n"
, status);
if
(status)
{
// Otherwise, terminate the VMX
DbgPrint(
"[*] VMCS failed to clear with status %d\n"
, status);
__vmx_off();
return
FALSE;
}
return
TRUE;
}
BOOLEAN
LoadVmcs(VIRTUAL_MACHINE_STATE * GuestState)
{
int
status = __vmx_vmptrld(&GuestState->VmcsRegion);
if
(status)
{
DbgPrint(
"[*] VMCS failed with status %d\n"
, status);
return
FALSE;
}
return
TRUE;
}
BOOLEAN
LoadVmcs(VIRTUAL_MACHINE_STATE * GuestState)
{
int
status = __vmx_vmptrld(&GuestState->VmcsRegion);
if
(status)
{
DbgPrint(
"[*] VMCS failed with status %d\n"
, status);
return
FALSE;
}
return
TRUE;
}
typedef
struct
_VIRTUAL_MACHINE_STATE
{
UINT64
VmxoRegion;
// VMXON region
UINT64
VmcsRegion;
// VMCS region
UINT64
Eptp;
// Extended-Page-Table Pointer
UINT64
VmmStack;
// Stack for VMM in VM-Exit State
UINT64
MsrBitmap;
// MSR Bitmap Virtual Address
UINT64
MsrBitmapPhysical;
// MSR Bitmap Physical Address
} VIRTUAL_MACHINE_STATE, *PVIRTUAL_MACHINE_STATE;
typedef
struct
_VIRTUAL_MACHINE_STATE
{
UINT64
VmxoRegion;
// VMXON region
UINT64
VmcsRegion;
// VMCS region
UINT64
Eptp;
// Extended-Page-Table Pointer
UINT64
VmmStack;
// Stack for VMM in VM-Exit State
UINT64
MsrBitmap;
// MSR Bitmap Virtual Address
UINT64
MsrBitmapPhysical;
// MSR Bitmap Physical Address
} VIRTUAL_MACHINE_STATE, *PVIRTUAL_MACHINE_STATE;
//
// Initiating EPTP and VMX
//
PEPTP EPTP = InitializeEptp();
InitiateVmx();
//
// Initiating EPTP and VMX
//
PEPTP EPTP = InitializeEptp();
InitiateVmx();
VOID
LaunchVm(
int
ProcessorID, PEPTP EPTP)
{
DbgPrint(
"\n======================== Launching VM =============================\n"
);
KAFFINITY AffinityMask;
AffinityMask = MathPower(2, ProcessorID);
KeSetSystemAffinityThread(AffinityMask);
DbgPrint(
"[*]\t\tCurrent thread is executing in %d th logical processor.\n"
, ProcessorID);
PAGED_CODE();
...
VOID
LaunchVm(
int
ProcessorID, PEPTP EPTP)
{
DbgPrint(
"\n======================== Launching VM =============================\n"
);
KAFFINITY AffinityMask;
AffinityMask = MathPower(2, ProcessorID);
KeSetSystemAffinityThread(AffinityMask);
DbgPrint(
"[*]\t\tCurrent thread is executing in %d th logical processor.\n"
, ProcessorID);
PAGED_CODE();
...
//
// Allocate stack for the VM Exit Handler
//
UINT64
VMM_STACK_VA = ExAllocatePoolWithTag(NonPagedPool, VMM_STACK_SIZE, POOLTAG);
g_GuestState[ProcessorID].VmmStack = VMM_STACK_VA;
if
(g_GuestState[ProcessorID].VmmStack == NULL)
{
DbgPrint(
"[*] Error in allocating VMM Stack.\n"
);
return
;
}
RtlZeroMemory(g_GuestState[ProcessorID].VmmStack, VMM_STACK_SIZE);
//
// Allocate stack for the VM Exit Handler
//
UINT64
VMM_STACK_VA = ExAllocatePoolWithTag(NonPagedPool, VMM_STACK_SIZE, POOLTAG);
g_GuestState[ProcessorID].VmmStack = VMM_STACK_VA;
if
(g_GuestState[ProcessorID].VmmStack == NULL)
{
DbgPrint(
"[*] Error in allocating VMM Stack.\n"
);
return
;
}
RtlZeroMemory(g_GuestState[ProcessorID].VmmStack, VMM_STACK_SIZE);
//
// Allocate memory for MSRBitMap
//
g_GuestState[ProcessorID].MsrBitmap = MmAllocateNonCachedMemory(PAGE_SIZE);
// should be aligned
if
(g_GuestState[ProcessorID].MsrBitmap == NULL)
{
DbgPrint(
"[*] Error in allocating MSRBitMap.\n"
);
return
;
}
RtlZeroMemory(g_GuestState[ProcessorID].MsrBitmap, PAGE_SIZE);
g_GuestState[ProcessorID].MsrBitmapPhysical = VirtualToPhysicalAddress(g_GuestState[ProcessorID].MsrBitmap);
//
// Allocate memory for MSRBitMap
//
g_GuestState[ProcessorID].MsrBitmap = MmAllocateNonCachedMemory(PAGE_SIZE);
// should be aligned
if
(g_GuestState[ProcessorID].MsrBitmap == NULL)
{
DbgPrint(
"[*] Error in allocating MSRBitMap.\n"
);
return
;
}
RtlZeroMemory(g_GuestState[ProcessorID].MsrBitmap, PAGE_SIZE);
g_GuestState[ProcessorID].MsrBitmapPhysical = VirtualToPhysicalAddress(g_GuestState[ProcessorID].MsrBitmap);
//
// Clear the VMCS State
//
if
(!ClearVmcsState(&g_GuestState[ProcessorID]))
{
goto
ErrorReturn;
}
//
// Load VMCS (Set the Current VMCS)
//
if
(!LoadVmcs(&g_GuestState[ProcessorID]))
{
goto
ErrorReturn;
}
//
// Clear the VMCS State
//
if
(!ClearVmcsState(&g_GuestState[ProcessorID]))
{
goto
ErrorReturn;
}
//
// Load VMCS (Set the Current VMCS)
//
if
(!LoadVmcs(&g_GuestState[ProcessorID]))
{
goto
ErrorReturn;
}
DbgPrint(
"[*] Setting up VMCS.\n"
);
SetupVmcs(&g_GuestState[ProcessorID], EPTP);
DbgPrint(
"[*] Setting up VMCS.\n"
);
SetupVmcs(&g_GuestState[ProcessorID], EPTP);
EXTERN g_StackPointerForReturning:QWORD
EXTERN g_BasePointerForReturning:QWORD
EXTERN g_StackPointerForReturning:QWORD
EXTERN g_BasePointerForReturning:QWORD
AsmSaveStateForVmxoff PROC PUBLIC
MOV g_StackPointerForReturning, RSP
MOV g_BasePointerForReturning, RBP
RET
AsmSaveStateForVmxoff ENDP
AsmSaveStateForVmxoff PROC PUBLIC
MOV g_StackPointerForReturning, RSP
MOV g_BasePointerForReturning, RBP
RET
AsmSaveStateForVmxoff ENDP
AsmVmxoffAndRestoreState PROC PUBLIC
VMXOFF ; turn it off before existing
MOV RSP, g_StackPointerForReturning
MOV RBP, g_BasePointerForReturning
; make rsp point to a correct
return
point
ADD RSP, 8
;
return
True
XOR RAX, RAX
MOV RAX, 1
;
return
section
MOV RBX, [RSP+28h+8h]
MOV RSI, [RSP+28h+10h]
ADD RSP, 020h
POP RDI
RET
AsmVmxoffAndRestoreState ENDP
AsmVmxoffAndRestoreState PROC PUBLIC
VMXOFF ; turn it off before existing
MOV RSP, g_StackPointerForReturning
MOV RBP, g_BasePointerForReturning
; make rsp point to a correct
return
point
ADD RSP, 8
;
return
True
XOR RAX, RAX
MOV RAX, 1
;
return
section
MOV RBX, [RSP+28h+8h]
MOV RSI, [RSP+28h+10h]
ADD RSP, 020h
POP RDI
RET
AsmVmxoffAndRestoreState ENDP
__vmx_vmlaunch();
//
// if VMLAUNCH succeeds will never be here!
//
ULONG64
ErrorCode = 0;
__vmx_vmread(VM_INSTRUCTION_ERROR, &ErrorCode);
__vmx_off();
DbgPrint(
"[*] VMLAUNCH Error : 0x%llx\n"
, ErrorCode);
DbgBreakPoint();
__vmx_vmlaunch();
//
// if VMLAUNCH succeeds will never be here!
//
ULONG64
ErrorCode = 0;
__vmx_vmread(VM_INSTRUCTION_ERROR, &ErrorCode);
__vmx_off();
DbgPrint(
"[*] VMLAUNCH Error : 0x%llx\n"
, ErrorCode);
DbgBreakPoint();
#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004
#define CPU_BASED_USE_TSC_OFFSETING 0x00000008
#define CPU_BASED_HLT_EXITING 0x00000080
#define CPU_BASED_INVLPG_EXITING 0x00000200
#define CPU_BASED_MWAIT_EXITING 0x00000400
#define CPU_BASED_RDPMC_EXITING 0x00000800
#define CPU_BASED_RDTSC_EXITING 0x00001000
#define CPU_BASED_CR3_LOAD_EXITING 0x00008000
#define CPU_BASED_CR3_STORE_EXITING 0x00010000
#define CPU_BASED_CR8_LOAD_EXITING 0x00080000
#define CPU_BASED_CR8_STORE_EXITING 0x00100000
#define CPU_BASED_TPR_SHADOW 0x00200000
#define CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000
#define CPU_BASED_MOV_DR_EXITING 0x00800000
#define CPU_BASED_UNCOND_IO_EXITING 0x01000000
#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000
#define CPU_BASED_MONITOR_TRAP_FLAG 0x08000000
#define CPU_BASED_ACTIVATE_MSR_BITMAP 0x10000000
#define CPU_BASED_MONITOR_EXITING 0x20000000
#define CPU_BASED_PAUSE_EXITING 0x40000000
#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000
#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004
#define CPU_BASED_USE_TSC_OFFSETING 0x00000008
#define CPU_BASED_HLT_EXITING 0x00000080
#define CPU_BASED_INVLPG_EXITING 0x00000200
#define CPU_BASED_MWAIT_EXITING 0x00000400
#define CPU_BASED_RDPMC_EXITING 0x00000800
#define CPU_BASED_RDTSC_EXITING 0x00001000
#define CPU_BASED_CR3_LOAD_EXITING 0x00008000
#define CPU_BASED_CR3_STORE_EXITING 0x00010000
#define CPU_BASED_CR8_LOAD_EXITING 0x00080000
#define CPU_BASED_CR8_STORE_EXITING 0x00100000
#define CPU_BASED_TPR_SHADOW 0x00200000
#define CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000
#define CPU_BASED_MOV_DR_EXITING 0x00800000
#define CPU_BASED_UNCOND_IO_EXITING 0x01000000
#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000
#define CPU_BASED_MONITOR_TRAP_FLAG 0x08000000
#define CPU_BASED_ACTIVATE_MSR_BITMAP 0x10000000
#define CPU_BASED_MONITOR_EXITING 0x20000000
#define CPU_BASED_PAUSE_EXITING 0x40000000
#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000
#define CPU_BASED_CTL2_ENABLE_EPT 0x2
#define CPU_BASED_CTL2_RDTSCP 0x8
#define CPU_BASED_CTL2_ENABLE_VPID 0x20
#define CPU_BASED_CTL2_UNRESTRICTED_GUEST 0x80
#define CPU_BASED_CTL2_ENABLE_VMFUNC 0x2000
#define CPU_BASED_CTL2_ENABLE_EPT 0x2
#define CPU_BASED_CTL2_RDTSCP 0x8
#define CPU_BASED_CTL2_ENABLE_VPID 0x20
#define CPU_BASED_CTL2_UNRESTRICTED_GUEST 0x80
#define CPU_BASED_CTL2_ENABLE_VMFUNC 0x2000
// VM-entry Control Bits
#define VM_ENTRY_IA32E_MODE 0x00000200
#define VM_ENTRY_SMM 0x00000400
#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800
#define VM_ENTRY_LOAD_GUEST_PAT 0x00004000
// VM-entry Control Bits
#define VM_ENTRY_IA32E_MODE 0x00000200
#define VM_ENTRY_SMM 0x00000400
#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800
#define VM_ENTRY_LOAD_GUEST_PAT 0x00004000
// VM-exit Control Bits
#define VM_EXIT_IA32E_MODE 0x00000200
#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
#define VM_EXIT_SAVE_GUEST_PAT 0x00040000
#define VM_EXIT_LOAD_HOST_PAT 0x00080000
// VM-exit Control Bits
#define VM_EXIT_IA32E_MODE 0x00000200
#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
#define VM_EXIT_SAVE_GUEST_PAT 0x00040000
#define VM_EXIT_LOAD_HOST_PAT 0x00080000
#define PIN_BASED_VM_EXECUTION_CONTROLS_EXTERNAL_INTERRUPT 0x00000001
#define PIN_BASED_VM_EXECUTION_CONTROLS_NMI_EXITING 0x00000008
#define PIN_BASED_VM_EXECUTION_CONTROLS_VIRTUAL_NMI 0x00000020
#define PIN_BASED_VM_EXECUTION_CONTROLS_ACTIVE_VMX_TIMER 0x00000040
#define PIN_BASED_VM_EXECUTION_CONTROLS_PROCESS_POSTED_INTERRUPTS 0x00000080
#define PIN_BASED_VM_EXECUTION_CONTROLS_EXTERNAL_INTERRUPT 0x00000001
#define PIN_BASED_VM_EXECUTION_CONTROLS_NMI_EXITING 0x00000008
#define PIN_BASED_VM_EXECUTION_CONTROLS_VIRTUAL_NMI 0x00000020
#define PIN_BASED_VM_EXECUTION_CONTROLS_ACTIVE_VMX_TIMER 0x00000040
#define PIN_BASED_VM_EXECUTION_CONTROLS_PROCESS_POSTED_INTERRUPTS 0x00000080
GetGdtBase PROC
LOCAL GDTR[10]:
BYTE
SGDT GDTR
MOV RAX, QWORD PTR GDTR[2]
RET
GetGdtBase ENDP
GetGdtBase PROC
LOCAL GDTR[10]:
BYTE
SGDT GDTR
MOV RAX, QWORD PTR GDTR[2]
RET
GetGdtBase ENDP
GetCs PROC
MOV RAX, CS
RET
GetCs ENDP
GetCs PROC
MOV RAX, CS
RET
GetCs ENDP
GetDs PROC
MOV RAX, DS
RET
GetDs ENDP
GetDs PROC
MOV RAX, DS
RET
GetDs ENDP
GetEs PROC
MOV RAX, ES
RET
GetEs ENDP
GetEs PROC
MOV RAX, ES
RET
GetEs ENDP
GetSs PROC
MOV RAX, SS
RET
GetSs ENDP
GetSs PROC
MOV RAX, SS
RET
GetSs ENDP
GetFs PROC
MOV RAX, FS
RET
GetFs ENDP
GetFs PROC
MOV RAX, FS
RET
GetFs ENDP
GetGs PROC
MOV RAX, GS
RET
GetGs ENDP
GetGs PROC
MOV RAX, GS
RET
GetGs ENDP
GetLdtr PROC
SLDT RAX
RET
GetLdtr ENDP
GetLdtr PROC
SLDT RAX
RET
GetLdtr ENDP
GetTr PROC
STR RAX
RET
GetTr ENDP
GetTr PROC
STR RAX
RET
GetTr ENDP
GetIdtBase PROC
LOCAL IDTR[10]:
BYTE
SIDT IDTR
MOV RAX, QWORD PTR IDTR[2]
RET
GetIdtBase ENDP
GetIdtBase PROC
LOCAL IDTR[10]:
BYTE
SIDT IDTR
MOV RAX, QWORD PTR IDTR[2]
RET
GetIdtBase ENDP
GetGdtLimit PROC
LOCAL GDTR[10]:
BYTE
SGDT GDTR
MOV AX,
WORD
PTR GDTR[0]
RET
GetGdtLimit ENDP
GetGdtLimit PROC
LOCAL GDTR[10]:
BYTE
SGDT GDTR
MOV AX,
WORD
PTR GDTR[0]
RET
GetGdtLimit ENDP
GetIdtLimit PROC
LOCAL IDTR[10]:
BYTE
SIDT IDTR
MOV AX,
WORD
PTR IDTR[0]
RET
GetIdtLimit ENDP
GetIdtLimit PROC
LOCAL IDTR[10]:
BYTE
SIDT IDTR
MOV AX,
WORD
PTR IDTR[0]
RET
GetIdtLimit ENDP
GetRflags PROC
PUSHFQ
POP RAX
RET
GetRflags ENDP
GetRflags PROC
PUSHFQ
POP RAX
RET
GetRflags ENDP
BOOLEAN
SetupVmcs(VIRTUAL_MACHINE_STATE * GuestState, PEPTP EPTP);
BOOLEAN
SetupVmcs(VIRTUAL_MACHINE_STATE * GuestState, PEPTP EPTP);
enum
VMCS_FIELDS {
GUEST_ES_SELECTOR = 0x00000800,
GUEST_CS_SELECTOR = 0x00000802,
GUEST_SS_SELECTOR = 0x00000804,
GUEST_DS_SELECTOR = 0x00000806,
GUEST_FS_SELECTOR = 0x00000808,
GUEST_GS_SELECTOR = 0x0000080a,
GUEST_LDTR_SELECTOR = 0x0000080c,
GUEST_TR_SELECTOR = 0x0000080e,
HOST_ES_SELECTOR = 0x00000c00,
HOST_CS_SELECTOR = 0x00000c02,
HOST_SS_SELECTOR = 0x00000c04,
HOST_DS_SELECTOR = 0x00000c06,
HOST_FS_SELECTOR = 0x00000c08,
HOST_GS_SELECTOR = 0x00000c0a,
HOST_TR_SELECTOR = 0x00000c0c,
IO_BITMAP_A = 0x00002000,
IO_BITMAP_A_HIGH = 0x00002001,
IO_BITMAP_B = 0x00002002,
IO_BITMAP_B_HIGH = 0x00002003,
MSR_BITMAP = 0x00002004,
MSR_BITMAP_HIGH = 0x00002005,
VM_EXIT_MSR_STORE_ADDR = 0x00002006,
VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007,
VM_EXIT_MSR_LOAD_ADDR = 0x00002008,
VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009,
VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a,
VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b,
TSC_OFFSET = 0x00002010,
TSC_OFFSET_HIGH = 0x00002011,
VIRTUAL_APIC_PAGE_ADDR = 0x00002012,
VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013,
VMFUNC_CONTROLS = 0x00002018,
VMFUNC_CONTROLS_HIGH = 0x00002019,
EPT_POINTER = 0x0000201A,
EPT_POINTER_HIGH = 0x0000201B,
EPTP_LIST = 0x00002024,
EPTP_LIST_HIGH = 0x00002025,
GUEST_PHYSICAL_ADDRESS = 0x2400,
GUEST_PHYSICAL_ADDRESS_HIGH = 0x2401,
VMCS_LINK_POINTER = 0x00002800,
VMCS_LINK_POINTER_HIGH = 0x00002801,
GUEST_IA32_DEBUGCTL = 0x00002802,
GUEST_IA32_DEBUGCTL_HIGH = 0x00002803,
PIN_BASED_VM_EXEC_CONTROL = 0x00004000,
CPU_BASED_VM_EXEC_CONTROL = 0x00004002,
EXCEPTION_BITMAP = 0x00004004,
PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,
PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,
CR3_TARGET_COUNT = 0x0000400a,
VM_EXIT_CONTROLS = 0x0000400c,
VM_EXIT_MSR_STORE_COUNT = 0x0000400e,
VM_EXIT_MSR_LOAD_COUNT = 0x00004010,
VM_ENTRY_CONTROLS = 0x00004012,
VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,
VM_ENTRY_INTR_INFO_FIELD = 0x00004016,
VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,
VM_ENTRY_INSTRUCTION_LEN = 0x0000401a,
TPR_THRESHOLD = 0x0000401c,
SECONDARY_VM_EXEC_CONTROL = 0x0000401e,
VM_INSTRUCTION_ERROR = 0x00004400,
VM_EXIT_REASON = 0x00004402,
VM_EXIT_INTR_INFO = 0x00004404,
VM_EXIT_INTR_ERROR_CODE = 0x00004406,
IDT_VECTORING_INFO_FIELD = 0x00004408,
IDT_VECTORING_ERROR_CODE = 0x0000440a,
VM_EXIT_INSTRUCTION_LEN = 0x0000440c,
VMX_INSTRUCTION_INFO = 0x0000440e,
GUEST_ES_LIMIT = 0x00004800,
GUEST_CS_LIMIT = 0x00004802,
GUEST_SS_LIMIT = 0x00004804,
GUEST_DS_LIMIT = 0x00004806,
GUEST_FS_LIMIT = 0x00004808,
GUEST_GS_LIMIT = 0x0000480a,
GUEST_LDTR_LIMIT = 0x0000480c,
GUEST_TR_LIMIT = 0x0000480e,
GUEST_GDTR_LIMIT = 0x00004810,
GUEST_IDTR_LIMIT = 0x00004812,
GUEST_ES_AR_BYTES = 0x00004814,
GUEST_CS_AR_BYTES = 0x00004816,
GUEST_SS_AR_BYTES = 0x00004818,
GUEST_DS_AR_BYTES = 0x0000481a,
GUEST_FS_AR_BYTES = 0x0000481c,
GUEST_GS_AR_BYTES = 0x0000481e,
GUEST_LDTR_AR_BYTES = 0x00004820,
GUEST_TR_AR_BYTES = 0x00004822,
GUEST_INTERRUPTIBILITY_INFO = 0x00004824,
GUEST_ACTIVITY_STATE = 0x00004826,
GUEST_SM_BASE = 0x00004828,
GUEST_SYSENTER_CS = 0x0000482A,
HOST_IA32_SYSENTER_CS = 0x00004c00,
CR0_GUEST_HOST_MASK = 0x00006000,
CR4_GUEST_HOST_MASK = 0x00006002,
CR0_READ_SHADOW = 0x00006004,
CR4_READ_SHADOW = 0x00006006,
CR3_TARGET_VALUE0 = 0x00006008,
CR3_TARGET_VALUE1 = 0x0000600a,
CR3_TARGET_VALUE2 = 0x0000600c,
CR3_TARGET_VALUE3 = 0x0000600e,
EXIT_QUALIFICATION = 0x00006400,
GUEST_LINEAR_ADDRESS = 0x0000640a,
GUEST_CR0 = 0x00006800,
GUEST_CR3 = 0x00006802,
GUEST_CR4 = 0x00006804,
GUEST_ES_BASE = 0x00006806,
GUEST_CS_BASE = 0x00006808,
GUEST_SS_BASE = 0x0000680a,
GUEST_DS_BASE = 0x0000680c,
GUEST_FS_BASE = 0x0000680e,
GUEST_GS_BASE = 0x00006810,
GUEST_LDTR_BASE = 0x00006812,
GUEST_TR_BASE = 0x00006814,
GUEST_GDTR_BASE = 0x00006816,
GUEST_IDTR_BASE = 0x00006818,
GUEST_DR7 = 0x0000681a,
GUEST_RSP = 0x0000681c,
GUEST_RIP = 0x0000681e,
GUEST_RFLAGS = 0x00006820,
GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822,
GUEST_SYSENTER_ESP = 0x00006824,
GUEST_SYSENTER_EIP = 0x00006826,
HOST_CR0 = 0x00006c00,
HOST_CR3 = 0x00006c02,
HOST_CR4 = 0x00006c04,
HOST_FS_BASE = 0x00006c06,
HOST_GS_BASE = 0x00006c08,
HOST_TR_BASE = 0x00006c0a,
HOST_GDTR_BASE = 0x00006c0c,
HOST_IDTR_BASE = 0x00006c0e,
HOST_IA32_SYSENTER_ESP = 0x00006c10,
HOST_IA32_SYSENTER_EIP = 0x00006c12,
HOST_RSP = 0x00006c14,
HOST_RIP = 0x00006c16,
};
enum
VMCS_FIELDS {
GUEST_ES_SELECTOR = 0x00000800,
GUEST_CS_SELECTOR = 0x00000802,
GUEST_SS_SELECTOR = 0x00000804,
GUEST_DS_SELECTOR = 0x00000806,
GUEST_FS_SELECTOR = 0x00000808,
GUEST_GS_SELECTOR = 0x0000080a,
GUEST_LDTR_SELECTOR = 0x0000080c,
GUEST_TR_SELECTOR = 0x0000080e,
HOST_ES_SELECTOR = 0x00000c00,
HOST_CS_SELECTOR = 0x00000c02,
HOST_SS_SELECTOR = 0x00000c04,
HOST_DS_SELECTOR = 0x00000c06,
HOST_FS_SELECTOR = 0x00000c08,
HOST_GS_SELECTOR = 0x00000c0a,
HOST_TR_SELECTOR = 0x00000c0c,
IO_BITMAP_A = 0x00002000,
IO_BITMAP_A_HIGH = 0x00002001,
IO_BITMAP_B = 0x00002002,
IO_BITMAP_B_HIGH = 0x00002003,
MSR_BITMAP = 0x00002004,
MSR_BITMAP_HIGH = 0x00002005,
VM_EXIT_MSR_STORE_ADDR = 0x00002006,
VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007,
VM_EXIT_MSR_LOAD_ADDR = 0x00002008,
VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009,
VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a,
VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b,
TSC_OFFSET = 0x00002010,
TSC_OFFSET_HIGH = 0x00002011,
VIRTUAL_APIC_PAGE_ADDR = 0x00002012,
VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013,
VMFUNC_CONTROLS = 0x00002018,
VMFUNC_CONTROLS_HIGH = 0x00002019,
EPT_POINTER = 0x0000201A,
EPT_POINTER_HIGH = 0x0000201B,
EPTP_LIST = 0x00002024,
EPTP_LIST_HIGH = 0x00002025,
GUEST_PHYSICAL_ADDRESS = 0x2400,
GUEST_PHYSICAL_ADDRESS_HIGH = 0x2401,
VMCS_LINK_POINTER = 0x00002800,
VMCS_LINK_POINTER_HIGH = 0x00002801,
GUEST_IA32_DEBUGCTL = 0x00002802,
GUEST_IA32_DEBUGCTL_HIGH = 0x00002803,
PIN_BASED_VM_EXEC_CONTROL = 0x00004000,
CPU_BASED_VM_EXEC_CONTROL = 0x00004002,
EXCEPTION_BITMAP = 0x00004004,
PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,
PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,
CR3_TARGET_COUNT = 0x0000400a,
VM_EXIT_CONTROLS = 0x0000400c,
VM_EXIT_MSR_STORE_COUNT = 0x0000400e,
VM_EXIT_MSR_LOAD_COUNT = 0x00004010,
VM_ENTRY_CONTROLS = 0x00004012,
VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,
VM_ENTRY_INTR_INFO_FIELD = 0x00004016,
VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,
VM_ENTRY_INSTRUCTION_LEN = 0x0000401a,
TPR_THRESHOLD = 0x0000401c,
SECONDARY_VM_EXEC_CONTROL = 0x0000401e,
VM_INSTRUCTION_ERROR = 0x00004400,
VM_EXIT_REASON = 0x00004402,
VM_EXIT_INTR_INFO = 0x00004404,
VM_EXIT_INTR_ERROR_CODE = 0x00004406,
IDT_VECTORING_INFO_FIELD = 0x00004408,
IDT_VECTORING_ERROR_CODE = 0x0000440a,
VM_EXIT_INSTRUCTION_LEN = 0x0000440c,
VMX_INSTRUCTION_INFO = 0x0000440e,
GUEST_ES_LIMIT = 0x00004800,
GUEST_CS_LIMIT = 0x00004802,
GUEST_SS_LIMIT = 0x00004804,
GUEST_DS_LIMIT = 0x00004806,
GUEST_FS_LIMIT = 0x00004808,
GUEST_GS_LIMIT = 0x0000480a,
GUEST_LDTR_LIMIT = 0x0000480c,
GUEST_TR_LIMIT = 0x0000480e,
GUEST_GDTR_LIMIT = 0x00004810,
GUEST_IDTR_LIMIT = 0x00004812,
GUEST_ES_AR_BYTES = 0x00004814,
GUEST_CS_AR_BYTES = 0x00004816,
GUEST_SS_AR_BYTES = 0x00004818,
GUEST_DS_AR_BYTES = 0x0000481a,
GUEST_FS_AR_BYTES = 0x0000481c,
GUEST_GS_AR_BYTES = 0x0000481e,
GUEST_LDTR_AR_BYTES = 0x00004820,
GUEST_TR_AR_BYTES = 0x00004822,
GUEST_INTERRUPTIBILITY_INFO = 0x00004824,
GUEST_ACTIVITY_STATE = 0x00004826,
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课