VT虚拟化调试器 – 第1部分:基本概念和配置测试环境

[复制链接]

该用户从未签到

2380

主题

2433

帖子

9139

积分

管理员

Rank: 9Rank: 9Rank: 9

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

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

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

x
大家好!

欢迎使用由“从头开始建立管理程序”的多部分教程系列的第一部分。顾名思义,本课程包含技术细节,用于基于硬件虚拟化创建基本的虚拟机。如果您学习本课程,则将能够创建自己的虚拟环境,并且将了解VMWare,VirtualBox,KVM和其他虚拟化软件如何使用处理器的功能来创建虚拟环境。

介绍
英特尔和AMD都在其现代CPU中支持虚拟化。英特尔于2005年11月13日在奔腾4系列中推出了代号为“ Vanderpool ”的(VT-x技术)。用于CPU标志VT-X能力是“ VMX ”它代表V irtual中号achineë X张力。

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

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

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

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

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

最后,我可能(并且肯定)会犯错误,例如错误的实现或错误的信息,或者忘记提及一些重要的描述,因此,如果我有任何错误,我应该提前对不起,对于每条告诉我我的错误的评论,我将感到高兴。技术信息或错误信息。

够了,让我们开始吧!

您需要的工具
您应该已安装WDK的Visual Studio。您可以在此处获取Windows Driver Kit(WDK)。

调试Windows的最佳方式和任何内核模式的事情是使用WinDBG的 是可以在Windows SDK的位置。(如果使用默认安装选项安装了WDK,则可能同时安装了WDK和SDK,因此可以跳过此步骤。)

您应该可以使用Windbg调试操作系统(在本例中为Windows),有关更多信息,请参见此处

Hex-rays IDA Pro是本教程的重要部分。

OSR Driver Loader可以在这里下载 ,我们使用此工具将驱动程序加载到Windows机器中。

SysInternals DebugView 用于打印DbgPrint()结果。

创建测试环境
本教程中的几乎所有代码都必须在内核级别运行,并且您必须设置Linux内核模块或Windows Driver Kit(WDK)模块。由于配置VMM涉及许多汇编代码,因此您应该知道如何在内核项目中运行内联汇编。在Linux中,您不需要做任何特别的事情,但是在Windows中,WDK不再在x64环境中支持内联汇编,因此,如果您以前没有解决此问题,则可能会很难创建一个简单的x64内联项目,但是不用担心,在我逐步解释的一篇文章中,我强烈建议您 在继续本部分的其余部分之前,先参见本主题来解决问题。

现在该创建驱动程序了!

如果您想从Windows Driver Kit(WDK)开始,这里有一篇很好的文章。

整个驱动程序是这样的:
  1. #include <ntddk.h>
  2. #include <wdf.h>
  3. #include <wdm.h>

  4. extern void inline AssemblyFunc1(void);
  5. extern void inline AssemblyFunc2(void);

  6. VOID DrvUnload(PDRIVER_OBJECT  DriverObject);
  7. NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath);

  8. #pragma alloc_text(INIT, DriverEntry)
  9. #pragma alloc_text(PAGE, Example_Unload)

  10. NTSTATUS DriverEntry(PDRIVER_OBJECT  pDriverObject, PUNICODE_STRING  pRegistryPath)
  11. {
  12.         NTSTATUS NtStatus = STATUS_SUCCESS;
  13.         UINT64 uiIndex = 0;
  14.         PDEVICE_OBJECT pDeviceObject = NULL;
  15.         UNICODE_STRING usDriverName, usDosDeviceName;

  16.         DbgPrint("DriverEntry Called.");

  17.         RtlInitUnicodeString(&usDriverName, L"\Device\MyHypervisor");
  18.         RtlInitUnicodeString(&usDosDeviceName, L"\DosDevices\MyHypervisor");

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

  20.         if (NtStatus == STATUS_SUCCESS)
  21.         {
  22.                 pDriverObject->DriverUnload = DrvUnload;
  23.                 pDeviceObject->Flags |= IO_TYPE_DEVICE;
  24.                 pDeviceObject->Flags &= (~DO_DEVICE_INITIALIZING);
  25.                 IoCreateSymbolicLink(&usDosDeviceName, &usDriverName);
  26.         }
  27.         return NtStatus;
  28. }

  29. VOID DrvUnload(PDRIVER_OBJECT  DriverObject)
  30. {
  31.         UNICODE_STRING usDosDeviceName;
  32.         DbgPrint("DrvUnload Called rn");
  33.         RtlInitUnicodeString(&usDosDeviceName, L"\DosDevices\MyHypervisor");
  34.         IoDeleteSymbolicLink(&usDosDeviceName);
  35.         IoDeleteDevice(DriverObject->DeviceObject);
  36. }
复制代码
AssemblyFunc1和 AssemblyFunc2 是定义为内联x64汇编代码的两个外部函数。

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

以下代码负责创建新设备:
  1. RtlInitUnicodeString(&usDriverName, L"\Device\MyHypervisor");
  2. RtlInitUnicodeString(&usDosDeviceName, L"\DosDevices\MyHypervisor");

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

  4.         if (NtStatus == STATUS_SUCCESS)
  5.         {
  6.                 pDriverObject->DriverUnload = DrvUnload;
  7.                 pDeviceObject->Flags |= IO_TYPE_DEVICE;
  8.                 pDeviceObject->Flags &= (~DO_DEVICE_INITIALIZING);
  9.                 IoCreateSymbolicLink(&usDosDeviceName, &usDriverName);
  10.         }
复制代码
如果使用Windows,则应禁用驱动程序签名强制执行以加载驱动程序,这是因为Microsoft阻止任何未经验证的代码在Windows内核(Ring 0)中运行。

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

单击 高级选项。
在新窗口中,单击“ 启动设置”。
点击 重启。
在“启动设置”屏幕上,按7或F7以禁用驱动程序签名强制实施。
我记得最近的事情是通过注册表启用Windows调试消息,通过这种方式,您可以通过SysInternals DebugView获得DbgPrint()结果。

只需执行以下步骤:

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

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

如果您无权访问物理机怎么办
Thas可以,您可以使用Vmware(或任何其他虚拟化产品)嵌套的虚拟化。只需确保将您的VMWare更新到最新版本(这很重要,因为VMWare有时在其先前版本的特殊版本上存在嵌套虚拟化的问题)。

然后确保在VM中启用以下功能。
另外,将您的VM设置为BIOS而不是UEFI。
所有驱动程序都在物理计算机和VMWare的嵌套虚拟化上进行了测试。

Hyper-V嵌套虚拟化
Hyper-V在许多方面与VMWare不同,因此您无法在Hyper-V的嵌套虚拟化上测试虚拟机监控程序。在第8部分中,我将描述如何以可在Hyper-V中使用的方式修改虚拟机管理程序,因此在第8部分之后,您将能够在Hyper-V的嵌套虚拟化上测试虚拟机管理程序。

开始之前的一些想法
在本系列的其余部分中,将经常使用一些关键字,您应该了解它们(大多数定义来自英特尔软件开发人员手册,第3C卷)。

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

来宾软件:每个虚拟机(VM)是一个来宾软件环境。

VMX根操作和VMX非根操作:VMM将以VMX根操作运行,而来宾软件将以VMX非根操作运行。

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

VM条目:过渡到VMX非根操作。

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

VM退出:从VMX非根操作到VMX根操作的过渡。

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

VMCS包含六个逻辑组:

来宾状态区域:处理器状态已保存到VM出口处的来宾状态区域中,并已加载到VM条目中。
主机状态区域:从VM出口上的主机状态区域加载的处理器状态。
VM执行控制字段:在VMX非root用户操作中控制处理器操作的字段。
VM退出控制字段:控制VM退出的字段。
VM条目控制字段:控制VM条目的字段。
VM退出信息字段:只读字段,用于接收有关VM退出的信息,描述VM退出的原因和性质。
我发现了一部出色的作品,可以说明VMCS
不用担心这些字段,我将在后面的部分中对它们中的大多数进行清楚的解释,只记得VMCS结构在不同版本的处理器之间会有所不同。

VMX说明
VMX引入了以下新说明。
Intel Mnemonic

Description

INVEPT
Invalidate Translations Derived from EPT
INVVPID
Invalidate Translations Based on VPID
VMCALL
Call to VM Monitor
VMCLEAR
Clear Virtual-Machine Control Structure
VMFUNC
Invoke VM function
VMLAUNCH
Launch Virtual Machine
VMRESUME
Resume Virtual Machine
VMPTRLD
Load Pointer to Virtual-Machine Control Structure
VMPTRST
Store Pointer to Virtual-Machine Control Structure
VMREAD
Read Field from Virtual-Machine Control Structure
VMWRITE
Write Field to Virtual-Machine Control Structure
VMXOFF
Leave VMX Operation
VMXON
Enter VMX Operation

VMM软件的生命周期

以下各项概述了VMM及其来宾软件的生命周期以及它们之间的交互:
软件通过执行VMXON指令进入VMX操作。
然后,使用VM条目,VMM可以将guest虚拟机变成VM(一次一个)。VMM使用指令VMLAUNCH和VMRESUME来实现VM条目。它使用VM出口重新获得控制权。
VM退出到VMM指定的入口点的传输控制。VMM可以采取适合于VM退出原因的操作,然后可以使用VM条目返回到VM。
最终,VMM可能决定关闭自身并退出VMX操作。它通过执行VMXOFF指令来实现。
现在就足够了!

在这一部分中,我解释了您应该了解的常规关键字,我们为以后的测试创建了一个简单的实验室。在下一部分中,我将解释如何使用上面创建的功能在您的计算机上启用VMX,然后在其余的虚拟化中进行调查,因此请确保检查博客以了解下一部分。

第二部分也可以在这里找到。
分享到:  QQ好友和群QQ好友和群
收藏收藏
回复

使用道具 举报

该用户从未签到

0

主题

11

帖子

11

积分

邀请会员

积分
11
沙发
发表于 2021-4-17 23:43:13 | 只看该作者
第一名学习打卡
回复 支持 反对

使用道具 举报

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

本版积分规则

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