woaidaima2016 发表于 2021-4-14 20:49:38

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

https://rayanfam.com/wp-content/uploads/sites/2/2018/08/Part2-Hypervisor.png

嗨,大家好,

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

在本节中,我们将学习检测处理器对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指针传递给内核驱动程序。

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

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

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

      RtlInitUnicodeString(&usDriverName, L"\\Device\\MyHypervisorDevice");
      
      RtlInitUnicodeString(&usDosDeviceName, L"\\DosDevices\\MyHypervisorDevice");

      NtStatus = IoCreateDevice(pDriverObject, 0, &usDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
      NTSTATUS NtStatusSymLinkResult = IoCreateSymbolicLink(&usDosDeviceName, &usDriverName);


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

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

                DbgPrint("[*] Setting Devices major functions.");
                pDriverObject->MajorFunction = DrvClose;
                pDriverObject->MajorFunction = DrvCreate;
                pDriverObject->MajorFunction = DrvIOCTLDispatcher;
                pDriverObject->MajorFunction = DrvRead;
                pDriverObject->MajorFunction = DrvWrite;

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

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

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

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

      return STATUS_SUCCESS;
}

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

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

      return STATUS_SUCCESS;
}

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

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

      return STATUS_SUCCESS;
}

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

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

      return STATUS_SUCCESS;
}
现在,让我们看看IRP MJ Functions列表和其他类型的Windows Driver Kit处理程序例程。
https://rayanfam.com/wp-content/uploads/sites/2/2018/08/anime1.png
IRP主要功能列表
这是IRP主要功能的列表,我们可以使用这些功能来执行不同的操作。

#define IRP_MJ_CREATE                   0x00
#define IRP_MJ_CREATE_NAMED_PIPE      0x01
#define IRP_MJ_CLOSE                  0x02
#define IRP_MJ_READ                     0x03
#define IRP_MJ_WRITE                  0x04
#define IRP_MJ_QUERY_INFORMATION      0x05
#define IRP_MJ_SET_INFORMATION          0x06
#define IRP_MJ_QUERY_EA               0x07
#define IRP_MJ_SET_EA                   0x08
#define IRP_MJ_FLUSH_BUFFERS            0x09
#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
#define IRP_MJ_SET_VOLUME_INFORMATION   0x0b
#define IRP_MJ_DIRECTORY_CONTROL      0x0c
#define IRP_MJ_FILE_SYSTEM_CONTROL      0x0d
#define IRP_MJ_DEVICE_CONTROL         0x0e
#define IRP_MJ_INTERNAL_DEVICE_CONTROL0x0f
#define IRP_MJ_SHUTDOWN               0x10
#define IRP_MJ_LOCK_CONTROL             0x11
#define IRP_MJ_CLEANUP                  0x12
#define IRP_MJ_CREATE_MAILSLOT          0x13
#define IRP_MJ_QUERY_SECURITY         0x14
#define IRP_MJ_SET_SECURITY             0x15
#define IRP_MJ_POWER                  0x16
#define IRP_MJ_SYSTEM_CONTROL         0x17
#define IRP_MJ_DEVICE_CHANGE            0x18
#define IRP_MJ_QUERY_QUOTA            0x19
#define IRP_MJ_SET_QUOTA                0x1a
#define IRP_MJ_PNP                      0x1b
#define IRP_MJ_PNP_POWER                IRP_MJ_PNP      // Obsolete....
#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次要功能的列表:

IRP_MN_START_DEVICE
IRP_MN_QUERY_STOP_DEVICE
IRP_MN_STOP_DEVICE
IRP_MN_CANCEL_STOP_DEVICE
IRP_MN_QUERY_REMOVE_DEVICE
IRP_MN_REMOVE_DEVICE
IRP_MN_CANCEL_REMOVE_DEVICE
IRP_MN_SURPRISE_REMOVAL
IRP_MN_QUERY_CAPABILITIES      
IRP_MN_QUERY_PNP_DEVICE_STATE
IRP_MN_FILTER_RESOURCE_REQUIREMENTS
IRP_MN_DEVICE_USAGE_NOTIFICATION
IRP_MN_QUERY_DEVICE_RELATIONS
IRP_MN_QUERY_RESOURCES
IRP_MN_QUERY_RESOURCE_REQUIREMENTS
IRP_MN_QUERY_ID
IRP_MN_QUERY_DEVICE_TEXT
IRP_MN_QUERY_BUS_INFORMATION
IRP_MN_QUERY_INTERFACE
IRP_MN_READ_CONFIG
IRP_MN_WRITE_CONFIG
IRP_MN_DEVICE_ENUMERATED
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调度表的定义是:

typedef struct _FAST_IO_DISPATCH {
ULONG                                  SizeOfFastIoDispatch;
PFAST_IO_CHECK_IF_POSSIBLE             FastIoCheckIfPossible;
PFAST_IO_READ                        FastIoRead;
PFAST_IO_WRITE                         FastIoWrite;
PFAST_IO_QUERY_BASIC_INFO            FastIoQueryBasicInfo;
PFAST_IO_QUERY_STANDARD_INFO         FastIoQueryStandardInfo;
PFAST_IO_LOCK                        FastIoLock;
PFAST_IO_UNLOCK_SINGLE               FastIoUnlockSingle;
PFAST_IO_UNLOCK_ALL                  FastIoUnlockAll;
PFAST_IO_UNLOCK_ALL_BY_KEY             FastIoUnlockAllByKey;
PFAST_IO_DEVICE_CONTROL                FastIoDeviceControl;
PFAST_IO_ACQUIRE_FILE                  AcquireFileForNtCreateSection;
PFAST_IO_RELEASE_FILE                  ReleaseFileForNtCreateSection;
PFAST_IO_DETACH_DEVICE               FastIoDetachDevice;
PFAST_IO_QUERY_NETWORK_OPEN_INFO       FastIoQueryNetworkOpenInfo;
PFAST_IO_ACQUIRE_FOR_MOD_WRITE         AcquireForModWrite;
PFAST_IO_MDL_READ                      MdlRead;
PFAST_IO_MDL_READ_COMPLETE             MdlReadComplete;
PFAST_IO_PREPARE_MDL_WRITE             PrepareMdlWrite;
PFAST_IO_MDL_WRITE_COMPLETE            MdlWriteComplete;
PFAST_IO_READ_COMPRESSED               FastIoReadCompressed;
PFAST_IO_WRITE_COMPRESSED            FastIoWriteCompressed;
PFAST_IO_MDL_READ_COMPLETE_COMPRESSEDMdlReadCompleteCompressed;
PFAST_IO_MDL_WRITE_COMPLETE_COMPRESSED MdlWriteCompleteCompressed;
PFAST_IO_QUERY_OPEN                  FastIoQueryOpen;
PFAST_IO_RELEASE_FOR_MOD_WRITE         ReleaseForModWrite;
PFAST_IO_ACQUIRE_FOR_CCFLUSH         AcquireForCcFlush;
PFAST_IO_RELEASE_FOR_CCFLUSH         ReleaseForCcFlush;
} FAST_IO_DISPATCH, *PFAST_IO_DISPATCH;定义的标题
我为驱动程序创建了以下标头(source.h)。

#pragma once
#include <ntddk.h>
#include <wdf.h>
#include <wdm.h>

extern void inline Breakpoint(void);
extern void inline Enable_VMX_Operation(void);


NTSTATUS DriverEntry(PDRIVER_OBJECTpDriverObject, PUNICODE_STRINGpRegistryPath);
VOID DrvUnload(PDRIVER_OBJECTDriverObject);
NTSTATUS DrvCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DrvRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DrvWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DrvClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DrvUnsupported(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DrvIOCTLDispatcher(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

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

#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DrvUnload)
#pragma alloc_text(PAGE, DrvCreate)
#pragma alloc_text(PAGE, DrvRead)
#pragma alloc_text(PAGE, DrvWrite)
#pragma alloc_text(PAGE, DrvClose)
#pragma alloc_text(PAGE, DrvUnsupported)
#pragma alloc_text(PAGE, DrvIOCTLDispatcher)



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

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

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

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

https://rayanfam.com/wp-content/uploads/sites/2/2018/08/osrdriverloader.png
现在回到DbgView,然后您应该看到驱动程序已成功加载,并显示一条消息[ DriverEntry。”应该出现。

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

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

https://rayanfam.com/wp-content/uploads/sites/2/2018/08/devices_winobg.png
DbgView的问题
不幸的是,由于某些未知原因,我无法查看DbgPrint()的结果。如果可以看到结果,则可以跳过此步骤,但是如果遇到问题,请执行以下步骤:

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

在regedit中,添加一个密钥:

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:
prlkd> x nt!kd_Default_Mask
fffff801`f5211808 nt!Kd_DEFAULT_Mask = <no type information>现在将其值更改为0xffffffff。lkd> eb fffff801`f5211808 ff ff ff ffhttps://rayanfam.com/wp-content/uploads/sites/2/2018/08/kd_DEFAULT_Mask.png
之后,您应该会看到结果,现在一切顺利。

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


https://rayanfam.com/wp-content/uploads/sites/2/2018/08/DbgView.png

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

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

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

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


string GetCpuID()
{
      //Initialize used variables
      char SysType; //Array consisting of 13 single bytes/characters
      string CpuID; //The string that will be used to add all the characters to
                                  //Starting coding in assembly language
      _asm
      {
                //Execute CPUID with EAX = 0 to get the CPU producer
                XOR EAX, EAX
                CPUID
                //MOV EBX to EAX and get the characters one by one by using shift out right bitwise operation.
                MOV EAX, EBX
                MOV SysType, al
                MOV SysType, ah
                SHR EAX, 16
                MOV SysType, al
                MOV SysType, ah
                //Get the second part the same way but these values are stored in EDX
                MOV EAX, EDX
                MOV SysType, al
                MOV SysType, ah
                SHR EAX, 16
                MOV SysType, al
                MOV SysType, ah
                //Get the third part
                MOV EAX, ECX
                MOV SysType, al
                MOV SysType, ah
                SHR EAX, 16
                MOV SysType, al
                MOV SysType, ah
                MOV SysType, 00
      }
      CpuID.assign(SysType, 12);
      return CpuID;
}最后一步是检查VMX是否存在,您可以使用以下代码进行检查:
bool VMX_Support_Detection()
{

      bool VMX = false;
      __asm {
                xor    eax, eax
                inc    eax
                cpuid
                bt   ecx, 0x5
                jc   VMXSupport
                VMXNotSupport :
                jmp   NopInstr
                VMXSupport :
                mov    VMX, 0x1
                NopInstr :
                nop
      }

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

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

int main()
{
      string CpuID;
      CpuID = GetCpuID();
      cout << "[*] The CPU Vendor is : " << CpuID << endl;
      if (CpuID == "GenuineIntel")
      {
                cout << "[*] The Processor virtualization technology is VT-x. \n";
      }
      else
      {
                cout << "[*] This program is not designed to run in a non-VT-x environemnt !\n";
                return 1;
      }
      
      if (VMX_Support_Detection())
      {
                cout << "[*] VMX Operation is supported by your processor .\n";
      }
      else
      {
                cout << "[*] VMX Operation is not supported by your processor .\n";
                return 1;
      }
      _getch();
    return 0;
}最终结果:
https://rayanfam.com/wp-content/uploads/sites/2/2018/08/VMXDetection.png
启用VMX操作
如果我们的处理器支持VMX Operation,则需要启用它的时间。正如我在上面告诉您的那样,IRP_MJ_CREATE 是应该用于启动操作的第一个函数。

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

在系统软件可以进入VMX操作之前,它会通过设置CR4.VMXE = 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)中声明您的函数:extern void inline Enable_VMX_Operation(void);
然后在汇编文件(在我的情况下为SourceAsm.asm)中添加此功能(将Cr4的第13(第14)位设置为1)。

<div>Enable_VMX_Operation PROC PUBLIC</div><div>push rax<span style="white-space:pre">                        </span>; Save the state</div><div>
</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>
</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的上面声明您的函数。

PUBLIC Enable_VMX_Operation上面的函数应该在DrvCreate中调用:


NTSTATUS DrvCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
        Enable_VMX_Operation();        // Enabling VMX Operation
        DbgPrint("[*] VMX Operation Enabled Successfully !");
        return STATUS_SUCCESS;
}最后,您应该从用户模式调用以下函数:
HANDLE hWnd = CreateFile(L"\\\\.\\MyHypervisorDevice",
                GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ |
                FILE_SHARE_WRITE,
                NULL, /// lpSecurityAttirbutes
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL |
                FILE_FLAG_OVERLAPPED,
                NULL); /// lpTemplateFile 如果看到以下结果,则说明您已成功完成第二部分。
https://rayanfam.com/wp-content/uploads/sites/2/2018/08/final-pic.png
重要说明:请注意,.asm文件的名称应与驱动程序主文件(.c文件)的名称不同,例如,如果驱动程序文件为“ Source.c”,则使用名称“ Source.asm”会导致奇怪的链接错误在Visual Studio中,应将.asm文件的名称更改为“ SourceAsm.asm”之类的名称,以避免出现此类链接器错误。

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

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


注意:请记住,虚拟机管理程序会随时间变化,因为操作系统中添加了新功能或使用了新技术,例如,对Meltdown&Spectre的更新对虚拟机管理程序进行了很多更改,因此,如果要使用虚拟机管理程序从头开始在您的项目,研究或任何工作中,您必须使用本系列教程的最新部分中的驱动程序,因为本教程已得到积极更新,并且更改已应用于较新的部分(保持较早的部分不变),因此您可能会遇到错误和因此,较早部分的不稳定问题确保在实际项目中使用最新部分。
页: [1]
查看完整版本: VT虚拟化调试器 – 第2部分:进入VMX操作