c++ windows forms 使用_从头开始了解和使用Hypervisor(第1部分)

476483d1-b21d-eb11-8da9-e4434bdf6706.gif

486483d1-b21d-eb11-8da9-e4434bdf6706.png

毫不夸张地说,学习完本文,你完全可以创建自己的虚拟环境,并且可以了解VMWare,VirtualBox,KVM和其他虚拟化软件如何使用处理器的函数来创建虚拟环境。

Intel和AMD都在其现代CPU中支持虚拟化,Intel于2005年11月13日在奔腾4系列中推出了代号为“Vanderpool”的VT-x技术,VT-x是intel运用Virtualization虚拟化技术中的一个指令集。VT-x函数的CPU标志是“vmx”,代表虚拟机扩展。

另一方面,AMD开发了代号为“Pacifica”的第一代虚拟化扩展,并最初以AMD安全虚拟机(SVM)的形式发布,但后来以AMD Virtualization的商标销售,缩写为AMD-V。

虚拟机管理程序有两种类型,类型1的管理程序称为“裸机管理程序”或“本机”,因为它可以直接在裸机物理服务器上运行,因此类型1的管理程序可以直接访问硬件。使用类型1虚拟机管理程序时,没有要加载的操作系统作为虚拟机管理程序。

与类型1管理程序相反,就像其他任何应用程序一样,类型2管理程序加载在操作系统内部。由于类型2虚拟机管理程序必须通过操作系统并由操作系统进行管理,因此类型2虚拟机管理程序(及其虚拟机)的运行效率(较慢)将低于类型1虚拟机管理程序。

关于虚拟化的更多概念是相同的,但是在VT-x和AMD-V中需要有不同的考虑。这些教程的其余部分主要关注VT-x,因为IntelCPU越来越流行,使用也越来越广泛。在我看来,AMD在其手册中更清晰地描述了虚拟化,但是Intel在某种程度上使读者感到困惑,尤其是在虚拟化文件中。

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png虚拟机管理程序和平台

这些概念是与平台无关的,我的意思是你可以在Linux或Windows中轻松运行相同的代码例程,并期望CPU产生相同的行为,但我更喜欢使用Windows,因为Windows更易于调试。在需要时提供一些Linux系统的示例。就个人而言,由于Linux内核管理#GP和其他异常之类的错误,并尝试避免内核崩溃并保持系统正常运行,因此它更适合测试虚拟机管理程序或与CPU相关的任何事物。另一方面,Windows从不尝试管理任何意外的异常,每当你不管理异常时,它都会导致蓝屏死机,因此你可能会收到很多BSOD。最后,我可能(并且肯定)会犯错误,例如错误的实现或错误的信息。

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png需要的工具

安装WDK的Visual Studio,你可以在此处获取Windows Driver Kit(WDK)。

调试Windows和任何内核模式的最佳方法是使用Windows SDK中提供的Windbg。如果使用默认安装选项安装了WDK,则可能同时安装了WDK和SDK,因此可以跳过此步骤。

你应该能够使用Windbg调试操作系统(在本文中为Windows),更多信息请参见此处。OSR驱动程序加载器可以在这里下载,我们使用此工具将驱动程序加载到Windows计算机中。用于打印DbgPrint()结果的SysInternals调试视图:

4d6483d1-b21d-eb11-8da9-e4434bdf6706.jpeg

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png 创建测试环境

本教程中几乎所有代码都必须在内核级别运行,并且你必须设置Linux内核模块或Windows Driver Kit(WDK)模块。由于配置VMM涉及许多汇编代码,因此你应该知道如何在内核项目中运行内联汇编。在Linux中,你不需要做任何特别的事情,但在Windows中,WDK不再支持x64环境中的内联汇编,因此,如果你以前没有解决此问题,则可能会很难创建一个简单的x64内联项目,但是不用担心,在我后面的文章中我会一一讲到。

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png现在该创建驱动程序了!

如果你想从Windows Driver Kit(WDK)开始,则整个驱动程序是这样的:

#include

#include

#include

extern void inline AssemblyFunc1(void);

extern void inline AssemblyFunc2(void);

VOID DrvUnload(PDRIVER_OBJECT  DriverObject);

NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath);

#pragma alloc_text(INIT, DriverEntry)

#pragma alloc_text(PAGE, Example_Unload)

NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath)

{

NTSTATUS NtStatus = STATUS_SUCCESS;

UINT64 uiIndex = 0;

PDEVICE_OBJECT pDeviceObject = NULL;

UNICODE_STRING usDriverName, usDosDeviceName;

DbgPrint("DriverEntry Called.");

RtlInitUnicodeString(&usDriverName, L"\Device\MyHypervisor");

RtlInitUnicodeString(&usDosDeviceName, L"\DosDevices\MyHypervisor");

NtStatus = IoCreateDevice(pDriverObject, 0, &usDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);

if (NtStatus == STATUS_SUCCESS)

{

pDriverObject->DriverUnload = DrvUnload;

pDeviceObject->Flags |= IO_TYPE_DEVICE;

pDeviceObject->Flags &= (~DO_DEVICE_INITIALIZING);

IoCreateSymbolicLink(&usDosDeviceName, &usDriverName);

}

return NtStatus;

}

VOID DrvUnload(PDRIVER_OBJECT  DriverObject)

{

UNICODE_STRING usDosDeviceName;

DbgPrint("DrvUnload Called rn");

RtlInitUnicodeString(&usDosDeviceName, L"\DosDevices\MyHypervisor");

IoDeleteSymbolicLink(&usDosDeviceName);

IoDeleteDevice(DriverObject->DeviceObject);

}

AssemblyFunc1和AssemblyFunc2是定义为内联x64汇编代码的两个外部函数。

我们的驱动程序需要注册一个设备,以便我们可以通过用户模式代码与虚拟环境进行通信,另一方面,我定义了使用PnP Windows驱动程序函数的DrvUnload,你可以轻松卸载驱动程序并删除设备,然后重新加载并创建一个新设备。以下代码会负责创建新设备:

RtlInitUnicodeString(&usDriverName, L"\Device\MyHypervisor");

RtlInitUnicodeString(&usDosDeviceName, L"\DosDevices\MyHypervisor");

NtStatus = IoCreateDevice(pDriverObject, 0, &usDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);

if (NtStatus == STATUS_SUCCESS)

{

pDriverObject->DriverUnload = DrvUnload;

pDeviceObject->Flags |= IO_TYPE_DEVICE;

pDeviceObject->Flags &= (~DO_DEVICE_INITIALIZING);

IoCreateSymbolicLink(&usDosDeviceName, &usDriverName);

}

如果你使用的是Windows,则应禁用驱动程序签名强制执行以加载驱动程序,这是因为Microsoft禁止任何未经验证的代码在Windows内核(Ring 0)中运行。

为此,请按住Shift键并重新启动计算机。你应该看到一个新窗口,然后:

1.单击高级选项;

2.在新窗口中,单击“启动设置”。

3.单击重新启动。

4.在“启动设置”屏幕上,按7或F7以禁用驱动程序签名;

526483d1-b21d-eb11-8da9-e4434bdf6706.png

通过注册表启用Windows调试消息,这样你就可以通过SysInternals DebugView获得DbgPrint()结果。

只需执行以下步骤:

1.在regedit中,添加一个密钥:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter

接着,添加一个名为IHVDRIVER的DWORD值,其值为0xFFFF。重新启动计算机,你就可以开始了。

不过在重新开始之前,你需要了解一些基本概念:

1.虚拟机监控器(VMM):VMM充当主机,并完全控制处理器和其他平台硬件,VMM能够保留对处理器资源,物理内存,中断管理和I/O的选择性控制。

2.客户软件(Guest Software):每个虚拟机(VM)是一个客户软件环境。

3.VMX根操作和VMX非根操作:VMM将以VMX根操作运行,而客户软件将以VMX非根操作运行。

4.VMX转换:VMX根操作和VMX非根操作之间的转换。

5.VM条目:转换为VMX非根操作。

6.扩展页表(EPT):一种现代机制,它使用第二层将客户物理地址转换为主机物理地址。

7.VM退出:从VMX非根操作转换为VMX根操作。

8.虚拟机控制结构(VMCS):是内存中的数据结构,每个虚拟机仅存在一次或者更精确地说,每个VCPU[虚拟CPU]只存在一次,而由VMM管理。随着不同VM之间执行上下文的每次更改,将为当前VM重启VMCS,从而使用VMCS定义VM的虚拟处理器和VMM控制客户软件的状态。

VMCS包含六个逻辑组:

1.客户状态区域:处理器状态已保存到VM退出处的客户状态区域中,并已加载到VM条目中;

2. 主机状态区域:从VM上的主机状态区域加载的处理器状态;

3.VM执行控制字段:在VMX非root用户操作中控制处理器操作的字段;

4. VM退出控制字段:控制VM退出的字段。

5. VM条目控制字段:控制VM条目的字段。

6.VM退出信息字段:只读字段,用于接收有关VM退出的信息,描述VM退出的原因和性质。

详见下图:

556483d1-b21d-eb11-8da9-e4434bdf6706.jpeg

不用担心这些字段,我将在后面的文章中对它们中的大多数进行清楚的解释,只要记住VMCS结构在不同版本的处理器之间是不同的即可。

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png VMX指令

VMX引入了以下新指令。

1.INVEPT:使EPT衍生的翻译无效

2.INVVPID:基于VPID的翻译无效

3. VMCALL:调用VM监控器;

4. VMCLEAR:清晰的虚拟机控制结构;

5. VMFUNC:VM调用函数;

6.VMLAUNCH:启动虚拟机;

7. VMRESUME:重启虚拟机;

8.VMPTRLD;指向虚拟机控制结构的载荷指针;

9.VMPTRST:存储指向虚拟机控制结构的指针;

10. VMREAD:从虚拟机控制结构读取字段;

11. VMREAD:将字段写入虚拟机控制结构;

12.VMXOFF:退出VMX操作;

13.VMXON:输入VMX操作;

4a6483d1-b21d-eb11-8da9-e4434bdf6706.pngVMM软件的运行周期

586483d1-b21d-eb11-8da9-e4434bdf6706.png

以下各项概述了VMM及其客户软件的生命周期以及它们之间的交互:

1.软件通过执行VMXON指令进入VMX操作;

2.然后,使用VM条目,VMM可以将客户虚拟机变成VM(一次一个)。VMM使用指令VMLAUNCH和VMRESUME来影响VM条目,它使用VM退出重新获得控制权。

3.VM退出到VMM指定的入口点的传输控制。VMM可以采取适合于VM退出原因的操作,然后可以使用VM条目返回到VM。

4.最终,VMM可能会自我关闭并退出VMX操作,它通过执行VMXOFF指令来实现。

接下来,我将说明如何使用上面创建的工具在计算机上启用VMX。 

4a6483d1-b21d-eb11-8da9-e4434bdf6706.pngIntel结构和常量(包括VT-x标头)

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

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png配置IRP主要函数

除了我们的内核模式驱动程序(“MyHypervisorDriver”)之外,我创建了一个用户模式应用程序称为“MyHypervisorApp”,首先,你应该在用户模式而不是内核模式中编写代码(源代码见此),这是因为你可能未处理异常,因此会导致BSOD,或者,另一方面,在内核模式下运行较少的代码,以减少出现漏洞的可能性。

如上所述,我们已经创建了一些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[uiIndex] = DrvUnsupported;

DbgPrint("[*] Setting Devices major functions.");

pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DrvClose;

pDriverObject->MajorFunction[IRP_MJ_CREATE] = DrvCreate;

pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvIOCTLDispatcher;

pDriverObject->MajorFunction[IRP_MJ_READ] = DrvRead;

pDriverObject->MajorFunction[IRP_MJ_WRITE] = 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 函数列表和其他类型的Windows Driver Kit处理程序例程。

5c6483d1-b21d-eb11-8da9-e4434bdf6706.png

4a6483d1-b21d-eb11-8da9-e4434bdf6706.pngIRP主要函数列表

这是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_CONTROL  0x0f

#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的函数,它已经有了变体,如用于ASCII和Unicode的CreateFileA和CreateFileW。因此我们每次调用CreateFile时,都会调用注册为IRP_MJ_CREATE的函数,或者如果我们调用ReadFile,则调用IRP_MJ_READ和WriteFile,最后IRP_MJ_WRITE被调用。你可以看到Windows将其设备视为文件,并且当调用该函数时,PIRP Irp中提供了从用户模式传递到内核模式所需的所有内容,作为缓冲区。

在本文的示例中,Windows负责将用户模式缓冲区复制到内核模式堆栈。不用担心,我们在项目的其余部分会经常使用它,但是在本部分中我们仅支持IRP_MJ_CREATE,而在以后的部分中则没有实现其他函数。

4a6483d1-b21d-eb11-8da9-e4434bdf6706.pngIRP次要函数

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

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png快速I/O

为了优化VMM,可以使用快速I/O,这是一种启动I/O操作的方法,该方法比IRP快,快速的I/O操作始终是同步的。

快速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_COMPRESSED  MdlReadCompleteCompressed;

  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;

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png定义标头文件

我为驱动程序创建了以下标头文件(source.h)。

#pragma once

#include

#include

#include

extern void inline Breakpoint(void);

extern void inline Enable_VMX_Operation(void);

NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath);

VOID DrvUnload(PDRIVER_OBJECT  DriverObject);

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

现在,只需编译驱动程序即可。

4a6483d1-b21d-eb11-8da9-e4434bdf6706.png加载驱动程序并检查设备是否存在

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

646483d1-b21d-eb11-8da9-e4434bdf6706.png

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

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

656483d1-b21d-eb11-8da9-e4434bdf6706.png

现在返回DbgView,你应该能够看到驱动程序已成功加载,并显示一条“[*] DriverEntry Called. ”消息。

如果没有问题,那就很好了;否则,如果DbgView有问题,还要进一步检查。

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

676483d1-b21d-eb11-8da9-e4434bdf6706.png

686483d1-b21d-eb11-8da9-e4434bdf6706.png

696483d1-b21d-eb11-8da9-e4434bdf6706.jpeg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值