VT虚拟化调试器 – 第2部分:进入VMX操作

[复制链接]

该用户从未签到

2380

主题

2433

帖子

9139

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9139
QQ
跳转到指定楼层
楼主
发表于 2021-4-14 20:49:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

想要查看内容赶紧注册登陆吧!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x


嗨,大家好,

首先,我强烈建议您在阅读本部分之前先阅读第一部分(基本概念和配置测试环境),因为它包含了您需要了解的基本知识为了了解本教程的其余部分。

在本节中,我们将学习检测处理器对Hypervisor的支持,然后简单地配置基本内容以启用VMX和进入VMX操作,以及有关Window Driver Kit(WDK)的更多信息。



配置我们的IRP主要功能
除了我们的内核模式驱动程序(“ MyHypervisorDriver ”)之外,我还创建了一个名为“ MyHypervisorApp ”的用户模式应用程序(首先,源代码在GitHub上可用),我应该鼓励您在用户中编写大部分代码-mode而不是kernel-mode,这是因为您可能未处理异常,因此会导致BSOD,或者,另一方面,在内核模式下运行较少的代码可减少放置某些讨厌的内核模式bug的可能性。

如果您记得上一部分,我们创建了一些Windows Driver Kit代码,现在我们要开发项目以支持更多的IRP主要功能。

IRP主要功能位于为每个设备创建的常规Windows表中,一旦在Windows中注册了设备,就必须在处理这些IRP主要功能时引入这些功能。这就像每个设备都有其主要功能表,并且每次用户模式应用程序调用其中的任何功能时,Windows都会根据用户请求的设备查找相应的功能(如果设备驱动程序支持该MJ功能),然后调用它然后将IRP指针传递给内核驱动程序。

现在,它负责设备功能以检查特权等。

以下代码创建设备:
  1. NTSTATUS NtStatus = STATUS_SUCCESS;
  2.         UINT64 uiIndex = 0;
  3.         PDEVICE_OBJECT pDeviceObject = NULL;
  4.         UNICODE_STRING usDriverName, usDosDeviceName;

  5.         DbgPrint("[*] DriverEntry Called.");        

  6.         RtlInitUnicodeString(&usDriverName, L"\\Device\\MyHypervisorDevice");
  7.         
  8.         RtlInitUnicodeString(&usDosDeviceName, L"\\DosDevices\\MyHypervisorDevice");

  9.         NtStatus = IoCreateDevice(pDriverObject, 0, &usDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
  10.         NTSTATUS NtStatusSymLinkResult = IoCreateSymbolicLink(&usDosDeviceName, &usDriverName);
复制代码



请注意,我们的设备名称为“ \ Device \ MyHypervisorDevice ” 。

之后,我们需要介绍设备的主要功能。
  1. if (NtStatus == STATUS_SUCCESS && NtStatusSymLinkResult == STATUS_SUCCESS)
  2.         {
  3.                 for (uiIndex = 0; uiIndex < IRP_MJ_MAXIMUM_FUNCTION; uiIndex++)
  4.                         pDriverObject->MajorFunction[uiIndex] = DrvUnsupported;

  5.                 DbgPrint("[*] Setting Devices major functions.");
  6.                 pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DrvClose;
  7.                 pDriverObject->MajorFunction[IRP_MJ_CREATE] = DrvCreate;
  8.                 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvIOCTLDispatcher;
  9.                 pDriverObject->MajorFunction[IRP_MJ_READ] = DrvRead;
  10.                 pDriverObject->MajorFunction[IRP_MJ_WRITE] = DrvWrite;

  11.                 pDriverObject->DriverUnload = DrvUnload;
  12.         }
  13.         else {
  14.                 DbgPrint("[*] There was some errors in creating device.");
  15.         }
复制代码
您可以看到我在所有功能上都加上了“ DrvUnsupported ”,这是一个处理所有MJ功能的功能,并告诉用户它不受支持。该函数的主体如下所示:
  1. NTSTATUS DrvUnsupported(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  2. {
  3.         DbgPrint("[*] This function is not supported :( !");

  4.         Irp->IoStatus.Status = STATUS_SUCCESS;
  5.         Irp->IoStatus.Information = 0;
  6.         IoCompleteRequest(Irp, IO_NO_INCREMENT);

  7.         return STATUS_SUCCESS;
  8. }
复制代码
我们还介绍了其他对我们的设备必不可少的主要功能,我们将在将来完成实现,让我们不理会它们。
  1. NTSTATUS DrvCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  2. {
  3.         DbgPrint("[*] Not implemented yet :( !");

  4.         Irp->IoStatus.Status = STATUS_SUCCESS;
  5.         Irp->IoStatus.Information = 0;
  6.         IoCompleteRequest(Irp, IO_NO_INCREMENT);

  7.         return STATUS_SUCCESS;
  8. }

  9. NTSTATUS DrvRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
  10. {
  11.         DbgPrint("[*] Not implemented yet :( !");

  12.         Irp->IoStatus.Status = STATUS_SUCCESS;
  13.         Irp->IoStatus.Information = 0;
  14.         IoCompleteRequest(Irp, IO_NO_INCREMENT);

  15.         return STATUS_SUCCESS;
  16. }

  17. NTSTATUS DrvWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  18. {
  19.         DbgPrint("[*] Not implemented yet :( !");

  20.         Irp->IoStatus.Status = STATUS_SUCCESS;
  21.         Irp->IoStatus.Information = 0;
  22.         IoCompleteRequest(Irp, IO_NO_INCREMENT);

  23.         return STATUS_SUCCESS;
  24. }

  25. NTSTATUS DrvClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  26. {
  27.         DbgPrint("[*] Not implemented yet :( !");

  28.         Irp->IoStatus.Status = STATUS_SUCCESS;
  29.         Irp->IoStatus.Information = 0;
  30.         IoCompleteRequest(Irp, IO_NO_INCREMENT);

  31.         return STATUS_SUCCESS;
  32. }
复制代码

现在,让我们看看IRP MJ Functions列表和其他类型的Windows Driver Kit处理程序例程。

IRP主要功能列表
这是IRP主要功能的列表,我们可以使用这些功能来执行不同的操作。

  1. #define IRP_MJ_CREATE                   0x00
  2. #define IRP_MJ_CREATE_NAMED_PIPE        0x01
  3. #define IRP_MJ_CLOSE                    0x02
  4. #define IRP_MJ_READ                     0x03
  5. #define IRP_MJ_WRITE                    0x04
  6. #define IRP_MJ_QUERY_INFORMATION        0x05
  7. #define IRP_MJ_SET_INFORMATION          0x06
  8. #define IRP_MJ_QUERY_EA                 0x07
  9. #define IRP_MJ_SET_EA                   0x08
  10. #define IRP_MJ_FLUSH_BUFFERS            0x09
  11. #define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
  12. #define IRP_MJ_SET_VOLUME_INFORMATION   0x0b
  13. #define IRP_MJ_DIRECTORY_CONTROL        0x0c
  14. #define IRP_MJ_FILE_SYSTEM_CONTROL      0x0d
  15. #define IRP_MJ_DEVICE_CONTROL           0x0e
  16. #define IRP_MJ_INTERNAL_DEVICE_CONTROL  0x0f
  17. #define IRP_MJ_SHUTDOWN                 0x10
  18. #define IRP_MJ_LOCK_CONTROL             0x11
  19. #define IRP_MJ_CLEANUP                  0x12
  20. #define IRP_MJ_CREATE_MAILSLOT          0x13
  21. #define IRP_MJ_QUERY_SECURITY           0x14
  22. #define IRP_MJ_SET_SECURITY             0x15
  23. #define IRP_MJ_POWER                    0x16
  24. #define IRP_MJ_SYSTEM_CONTROL           0x17
  25. #define IRP_MJ_DEVICE_CHANGE            0x18
  26. #define IRP_MJ_QUERY_QUOTA              0x19
  27. #define IRP_MJ_SET_QUOTA                0x1a
  28. #define IRP_MJ_PNP                      0x1b
  29. #define IRP_MJ_PNP_POWER                IRP_MJ_PNP      // Obsolete....
  30. #define IRP_MJ_MAXIMUM_FUNCTION         0x1b
复制代码
每个主要功能只有在我们从用户模式调用其相应功能时才会触发。例如,有一个叫功能(在用户模式)的CreateFile(及其所有像变种CreateFileA的和CreateFileW为ASCII和Unicode的),所以每次我们调用的CreateFile 已注册作为函数 IRP_MJ_CREATE 或将被称为如果我们调用的ReadFile然后 IRP_MJ_READ 和WriteFile 然后将调用IRP_MJ_WRITE 。您可以看到Windows将其设备视为文件,并且我们需要从用户模式传递到内核模式的所有内容都可以在 当调用函数时,PIRP Irp作为缓冲区。

在这种情况下,Windows负责将用户模式缓冲区复制到内核模式堆栈。

不用担心,我们在项目的其余部分中会经常使用它,但是在此部分中我们仅支持IRP_MJ_CREATE,而 在以后的部分中未实现其他功能。

IRP次要功能
IRP次要功能主要用于PnP管理器通知特殊事件,例如, PnP管理器  在将硬件资源(如果有)分配给设备后发送IRP_MN_START_DEVICE,或者PnP管理器发送IRP_MN_STOP_DEVICE来停止设备,以便它可以重新配置设备的硬件资源。

在本系列的后面部分,我们将需要这些次要功能。

以下是IRP次要功能的列表:

  1. IRP_MN_START_DEVICE
  2. IRP_MN_QUERY_STOP_DEVICE
  3. IRP_MN_STOP_DEVICE
  4. IRP_MN_CANCEL_STOP_DEVICE
  5. IRP_MN_QUERY_REMOVE_DEVICE
  6. IRP_MN_REMOVE_DEVICE
  7. IRP_MN_CANCEL_REMOVE_DEVICE
  8. IRP_MN_SURPRISE_REMOVAL
  9. IRP_MN_QUERY_CAPABILITIES        
  10. IRP_MN_QUERY_PNP_DEVICE_STATE
  11. IRP_MN_FILTER_RESOURCE_REQUIREMENTS
  12. IRP_MN_DEVICE_USAGE_NOTIFICATION
  13. IRP_MN_QUERY_DEVICE_RELATIONS
  14. IRP_MN_QUERY_RESOURCES
  15. IRP_MN_QUERY_RESOURCE_REQUIREMENTS
  16. IRP_MN_QUERY_ID
  17. IRP_MN_QUERY_DEVICE_TEXT
  18. IRP_MN_QUERY_BUS_INFORMATION
  19. IRP_MN_QUERY_INTERFACE
  20. IRP_MN_READ_CONFIG
  21. IRP_MN_WRITE_CONFIG
  22. IRP_MN_DEVICE_ENUMERATED
  23. IRP_MN_SET_LOCK
复制代码
快速I / O
为了优化VMM,可以使用快速I / O,这是一种启动I / O操作的方法,该方法比IRP更快。快速的I / O操作始终是同步的。

根据MSDN:

快速I / O是专门为缓存文件上的快速同步I / O设计的。在快速I / O操作中,数据直接在用户缓冲区和系统缓存之间传输,而绕过文件系统和存储驱动程序堆栈。(存储驱动程序不使用快速I / O。)如果在接收到快速I / O读或写请求时从文件读取的所有数据都驻留在系统缓存中,则该请求将立即得到满足。

当I / O管理器收到对同步文件I / O(而不是分页I / O)的请求时,它将首先调用快速I / O例程。如果快速I / O例程返回 TRUE,则该操作由快速I / O例程进行服务。如果快速I / O例程返回 FALSE,则I / O管理器将创建并发送IRP。

快速I / O调度表的定义是:

  1. typedef struct _FAST_IO_DISPATCH {
  2.   ULONG                                  SizeOfFastIoDispatch;
  3.   PFAST_IO_CHECK_IF_POSSIBLE             FastIoCheckIfPossible;
  4.   PFAST_IO_READ                          FastIoRead;
  5.   PFAST_IO_WRITE                         FastIoWrite;
  6.   PFAST_IO_QUERY_BASIC_INFO              FastIoQueryBasicInfo;
  7.   PFAST_IO_QUERY_STANDARD_INFO           FastIoQueryStandardInfo;
  8.   PFAST_IO_LOCK                          FastIoLock;
  9.   PFAST_IO_UNLOCK_SINGLE                 FastIoUnlockSingle;
  10.   PFAST_IO_UNLOCK_ALL                    FastIoUnlockAll;
  11.   PFAST_IO_UNLOCK_ALL_BY_KEY             FastIoUnlockAllByKey;
  12.   PFAST_IO_DEVICE_CONTROL                FastIoDeviceControl;
  13.   PFAST_IO_ACQUIRE_FILE                  AcquireFileForNtCreateSection;
  14.   PFAST_IO_RELEASE_FILE                  ReleaseFileForNtCreateSection;
  15.   PFAST_IO_DETACH_DEVICE                 FastIoDetachDevice;
  16.   PFAST_IO_QUERY_NETWORK_OPEN_INFO       FastIoQueryNetworkOpenInfo;
  17.   PFAST_IO_ACQUIRE_FOR_MOD_WRITE         AcquireForModWrite;
  18.   PFAST_IO_MDL_READ                      MdlRead;
  19.   PFAST_IO_MDL_READ_COMPLETE             MdlReadComplete;
  20.   PFAST_IO_PREPARE_MDL_WRITE             PrepareMdlWrite;
  21.   PFAST_IO_MDL_WRITE_COMPLETE            MdlWriteComplete;
  22.   PFAST_IO_READ_COMPRESSED               FastIoReadCompressed;
  23.   PFAST_IO_WRITE_COMPRESSED              FastIoWriteCompressed;
  24.   PFAST_IO_MDL_READ_COMPLETE_COMPRESSED  MdlReadCompleteCompressed;
  25.   PFAST_IO_MDL_WRITE_COMPLETE_COMPRESSED MdlWriteCompleteCompressed;
  26.   PFAST_IO_QUERY_OPEN                    FastIoQueryOpen;
  27.   PFAST_IO_RELEASE_FOR_MOD_WRITE         ReleaseForModWrite;
  28.   PFAST_IO_ACQUIRE_FOR_CCFLUSH           AcquireForCcFlush;
  29.   PFAST_IO_RELEASE_FOR_CCFLUSH           ReleaseForCcFlush;
  30. } FAST_IO_DISPATCH, *PFAST_IO_DISPATCH;
复制代码
定义的标题
我为驱动程序创建了以下标头(source.h)。

  1. #pragma once
  2. #include <ntddk.h>
  3. #include <wdf.h>
  4. #include <wdm.h>

  5. extern void inline Breakpoint(void);
  6. extern void inline Enable_VMX_Operation(void);


  7. NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath);
  8. VOID DrvUnload(PDRIVER_OBJECT  DriverObject);
  9. NTSTATUS DrvCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  10. NTSTATUS DrvRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  11. NTSTATUS DrvWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  12. NTSTATUS DrvClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  13. NTSTATUS DrvUnsupported(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  14. NTSTATUS DrvIOCTLDispatcher(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

  15. VOID PrintChars(_In_reads_(CountChars) PCHAR BufferAddress, _In_ size_t CountChars);
  16. VOID PrintIrpInfo(PIRP Irp);

  17. #pragma alloc_text(INIT, DriverEntry)
  18. #pragma alloc_text(PAGE, DrvUnload)
  19. #pragma alloc_text(PAGE, DrvCreate)
  20. #pragma alloc_text(PAGE, DrvRead)
  21. #pragma alloc_text(PAGE, DrvWrite)
  22. #pragma alloc_text(PAGE, DrvClose)
  23. #pragma alloc_text(PAGE, DrvUnsupported)
  24. #pragma alloc_text(PAGE, DrvIOCTLDispatcher)



  25. // IOCTL Codes and Its meanings
  26. #define IOCTL_TEST 0x1 // In case of testing
复制代码
现在,只需编译您的驱动程序即可。

加载驱动程序并检查设备是否存在
为了加载我们的驱动程序(MyHypervisorDriver),首先下载OSR Driver Loader,然后以管理员身份运行Sysinternals DbgView,确保您的DbgView捕获了内核(您可以通过Capture-> Capture Kernel进行检查)。


之后,打开OSR Driver Loader(转到OsrLoader-> kit-> WNET-> AMD64-> FRE)并打开OSRLOADER.exe(在x64环境中)。现在,如果您构建了驱动程序,则在OSR驱动程序加载程序中找到.sys文件(在MyHypervisorDriver \ x64 \ Debug \应该是名为“ MyHypervisorDriver.sys”的文件)中,单击浏览并选择(MyHypervisorDriver.sys),然后单击以在显示驱动程序已成功注册的消息框后的“注册服务”,您应单击“启动服务”。

请注意,您应该为Visual Studio安装了WDK ,以便能够构建您的项目。


现在回到DbgView,然后您应该看到驱动程序已成功加载,并显示一条消息[ DriverEntry。”应该出现。

如果没有问题,那就很好了,否则,如果DbgView有问题,则可以检查下一步。

请记住,现在您已经注册了驱动程序,因此可以使用SysInternals WinObj来查看“ MyHypervisorDevice ”是否可用。


DbgView的问题
不幸的是,由于某些未知原因,我无法查看DbgPrint()的结果。如果可以看到结果,则可以跳过此步骤,但是如果遇到问题,请执行以下步骤:

正如我在第1部分中提到的:

在regedit中,添加一个密钥:

  1. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter
复制代码
在其下,添加一个名为IHVDRIVER的DWORD值,其值为0xFFFF

重新启动计算机,您就可以开始了。

它始终对我有用,并且我在许多计算机上进行了测试,但是我的MacBook似乎有问题。

为了解决此问题,您需要找到一个名为nt!Kd_DEFAULT_Mask的Windows内核全局变量 , 该变量负责在DbgView中显示结果,它有一个我不知道的掩码,所以我只输入了0xffffffff使其简单地显示所有内容!

为此,您需要使用Windbg进行Windows本地内核调试。

以管理员身份打开命令提示符窗口。在上输入 bcdedit / debug
如果尚未将计算机配置为调试传输的目标,请输入 bcdedit / dbgsettings local
重新启动计算机。
之后,您需要使用UAC管理员权限打开Windbg,转到“文件”>“内核调试”>“本地”>按“确定”,然后 使用以下命令在本地Windbg中找到 nt!Kd_DEFAULT_Mask:
  1. prlkd> x nt!kd_Default_Mask
  2. fffff801`f5211808 nt!Kd_DEFAULT_Mask = <no type information>
复制代码
现在将其值更改为0xffffffff。
  1. lkd> eb fffff801`f5211808 ff ff ff ff
复制代码

之后,您应该会看到结果,现在一切顺利。

请记住,这是本主题其余部分必不可少的步骤,因为如果我们看不到任何内核详细信息,那么我们将无法调试。




检测虚拟机监控程序支持
在启用VT-x之前,应该首先考虑发现对vmx的支持,这在《英特尔软件开发人员手册》第3C卷第23.6节“为VMX发现支持”中已介绍。

如果CPUID.1:ECX.VMX [bit 5] = 1,则可以使用CPUID知道VMX的存在,然后支持VMX操作。

首先,我们需要知道我们是否在基于Intel的处理器上运行,这可以通过检查CPUID指令并找到供应商字符串“ GenuineIntel ”来理解。

以下函数以CPUID指令的形式返回供应商字符串。


  1. string GetCpuID()
  2. {
  3.         //Initialize used variables
  4.         char SysType[13]; //Array consisting of 13 single bytes/characters
  5.         string CpuID; //The string that will be used to add all the characters to
  6.                                   //Starting coding in assembly language
  7.         _asm
  8.         {
  9.                 //Execute CPUID with EAX = 0 to get the CPU producer
  10.                 XOR EAX, EAX
  11.                 CPUID
  12.                 //MOV EBX to EAX and get the characters one by one by using shift out right bitwise operation.
  13.                 MOV EAX, EBX
  14.                 MOV SysType[0], al
  15.                 MOV SysType[1], ah
  16.                 SHR EAX, 16
  17.                 MOV SysType[2], al
  18.                 MOV SysType[3], ah
  19.                 //Get the second part the same way but these values are stored in EDX
  20.                 MOV EAX, EDX
  21.                 MOV SysType[4], al
  22.                 MOV SysType[5], ah
  23.                 SHR EAX, 16
  24.                 MOV SysType[6], al
  25.                 MOV SysType[7], ah
  26.                 //Get the third part
  27.                 MOV EAX, ECX
  28.                 MOV SysType[8], al
  29.                 MOV SysType[9], ah
  30.                 SHR EAX, 16
  31.                 MOV SysType[10], al
  32.                 MOV SysType[11], ah
  33.                 MOV SysType[12], 00
  34.         }
  35.         CpuID.assign(SysType, 12);
  36.         return CpuID;
  37. }
复制代码
最后一步是检查VMX是否存在,您可以使用以下代码进行检查:
  1. bool VMX_Support_Detection()
  2. {

  3.         bool VMX = false;
  4.         __asm {
  5.                 xor    eax, eax
  6.                 inc    eax
  7.                 cpuid
  8.                 bt     ecx, 0x5
  9.                 jc     VMXSupport
  10.                 VMXNotSupport :
  11.                 jmp     NopInstr
  12.                 VMXSupport :
  13.                 mov    VMX, 0x1
  14.                 NopInstr :
  15.                 nop
  16.         }

  17.         return VMX;
  18. }
复制代码
如您所见,它检查EAX = 1的CPUID,并且如果第5(第6)位为1,则支持VMX操作。我们还可以在内核驱动程序中执行相同的操作。

总而言之,我们的主要代码应该是这样的:

  1. int main()
  2. {
  3.         string CpuID;
  4.         CpuID = GetCpuID();
  5.         cout << "[*] The CPU Vendor is : " << CpuID << endl;
  6.         if (CpuID == "GenuineIntel")
  7.         {
  8.                 cout << "[*] The Processor virtualization technology is VT-x. \n";
  9.         }
  10.         else
  11.         {
  12.                 cout << "[*] This program is not designed to run in a non-VT-x environemnt !\n";
  13.                 return 1;
  14.         }
  15.         
  16.         if (VMX_Support_Detection())
  17.         {
  18.                 cout << "[*] VMX Operation is supported by your processor .\n";
  19.         }
  20.         else
  21.         {
  22.                 cout << "[*] VMX Operation is not supported by your processor .\n";
  23.                 return 1;
  24.         }
  25.         _getch();
  26.     return 0;
  27. }
复制代码
最终结果:

启用VMX操作
如果我们的处理器支持VMX Operation,则需要启用它的时间。正如我在上面告诉您的那样,  IRP_MJ_CREATE 是应该用于启动操作的第一个函数。

形成英特尔软件开发人员手册(23.7启用和输入VMX操作):

在系统软件可以进入VMX操作之前,它会通过设置CR4.VMXE [bit 13] = 1来启用VMX。然后通过执行VMXON指令进入VMX操作。如果以CR4.VMXE = 0执行,VMXON会导致无效操作码异常(#UD)。一旦进入VMX操作,就无法清除CR4.VMXE。系统软件通过执行VMXOFF指令退出VMX操作。执行VMXOFF后,​​可以在VMX操作之外清除CR4.VMXE。
VMXON也由IA32_FEATURE_CONTROL MSR(MSR地址3AH)控制。复位逻辑处理器后,此MSR清除为零。MSR的相关位是:

位0是锁定位。如果清除此位,则VMXON会导致常规保护异常。如果设置了锁定位,则此MSR的WRMSR会导致一般保护异常;除非上电复位条件,否则不能修改MSR。系统BIOS可以使用此位为BIOS提供设置选项,以禁用对VMX的支持。要在平台上启用VMX支持,BIOS必须将位1,位2或两者都设置,以及锁定位。
位1使能SMX操作中的VMXON。如果清除此位,则在SMX操作中执行VMXON会导致常规保护异常。尝试在既不支持VMX操作又不支持SMX操作的逻辑处理器上将该位置1,会导致一般保护异常。
位2启用SMX之外的VMXON操作。如果清除此位,则在SMX操作之外执行VMXON会导致常规保护异常。尝试在不支持VMX操作的逻辑处理器上将该位置1会导致一般保护异常。
将CR4 VMXE位置1
您还记得我之前告诉您的如何在Windows Driver Kit x64中创建内联程序集的部分吗?

现在,您应该创建一些函数以在汇编中执行此操作。

仅在头文件(在我的情况下为S ource.h)中声明您的函数:
  1. extern void inline Enable_VMX_Operation(void);
复制代码

然后在汇编文件(在我的情况下为SourceAsm.asm)中添加此功能(将Cr4的第13(第14)位设置为1)。

  1. <div>Enable_VMX_Operation PROC PUBLIC</div><div>push rax<span style="white-space:pre">                        </span>; Save the state</div><div>
  2. </div><div>xor rax,rax<span style="white-space:pre">                        </span>; Clear the RAX</div><div>mov rax,cr4</div><div>or rax,02000h<span style="white-space:pre">                </span>        ; Set the 14th bit</div><div>mov cr4,rax</div><div>
  3. </div><div>pop rax<span style="white-space:pre">                                </span>; Restore the state</div><div>ret</div><div>Enable_VMX_Operation ENDP</div>
复制代码



另外,在SourceAsm.asm的上面声明您的函数。

  1. PUBLIC Enable_VMX_Operation
复制代码
上面的函数应该在DrvCreate中调用:


  1. NTSTATUS DrvCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  2. {
  3.         Enable_VMX_Operation();        // Enabling VMX Operation
  4.         DbgPrint("[*] VMX Operation Enabled Successfully !");
  5.         return STATUS_SUCCESS;
  6. }
复制代码
最后,您应该从用户模式调用以下函数:
  1. HANDLE hWnd = CreateFile(L"\\\\.\\MyHypervisorDevice",
  2.                 GENERIC_READ | GENERIC_WRITE,
  3.                 FILE_SHARE_READ |
  4.                 FILE_SHARE_WRITE,
  5.                 NULL, /// lpSecurityAttirbutes
  6.                 OPEN_EXISTING,
  7.                 FILE_ATTRIBUTE_NORMAL |
  8.                 FILE_FLAG_OVERLAPPED,
  9.                 NULL); /// lpTemplateFile
复制代码
如果看到以下结果,则说明您已成功完成第二部分。

重要说明:请注意,.asm文件的名称应与驱动程序主文件(.c文件)的名称不同,例如,如果驱动程序文件为“ Source.c”,则使用名称“ Source.asm”会导致奇怪的链接错误在Visual Studio中,应将.asm文件的名称更改为“ SourceAsm.asm”之类的名称,以避免出现此类链接器错误。

结论
在这一部分中,您了解了创建Windows Driver Kit程序所需了解的基本知识,然后我们进入了虚拟环境,因此我们为其余部分奠定了基础。

在第三部分中,我们对Intel VT-x有了更深入的了解,并使我们的驱动程序更加先进,请耐心等待,它将很快准备就绪!


注意:请记住,虚拟机管理程序会随时间变化,因为操作系统中添加了新功能或使用了新技术,例如,对Meltdown&Spectre的更新对虚拟机管理程序进行了很多更改,因此,如果要使用虚拟机管理程序从头开始在您的项目,研究或任何工作中,您必须使用本系列教程的最新部分中的驱动程序,因为本教程已得到积极更新,并且更改已应用于较新的部分(保持较早的部分不变),因此您可能会遇到错误和因此,较早部分的不稳定问题确保在实际项目中使用最新部分。
分享到:  QQ好友和群QQ好友和群
收藏收藏
回复

使用道具 举报

快速回复高级模式
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表