GProtect EPT Driver
GProtect VT EPT Hook 驱动
Virtualization Technology 是一种硬件虚拟化技术,在硬件虚拟化技术中,一个重要的概念是VMM(Virtual Machine Monitor),它专指使用硬件虚拟化技术创建出的特权层,该层提供给虚拟机开发者,用来实现虚拟硬件与真实硬件的通讯和一些事情处理操作,因此VMM中的权限要大于操作系统,如果操作系统驱动处于ring0 层,那么可以将客户机的操作系统放到虚拟机中进行管理的VMM就处于 ring -1 层。 在这里简述下 vt ept hook的原理 首先检测下 当前CPU是否支持 VT,参考Intel手册 Volume 3: System Programming Guide
根据手册编写检测代码,通过 cpuid 检测 ecx.vmx 中第五位是否不为1
CPUID Registers = { 0 };
__cpuid((int*)&Registers, 1);
if ((Registers.ecx & (1 << 5)) == 0) {
return FALSE;
}
return TRUE;
IA32_FEATURE_CONTROL_MSR Control = { 0 };
Control.All = __readmsr(MSR_IA32_FEATURE_CONTROL);
if (Control.Fields.Lock != 1) {
return FALSE;
}
return TRUE;
CR0_REG Cr0Register = { 0 };
Cr0Register.All = __readcr0();
if (Cr0Register.Fields.PE != 1 ||
Cr0Register.Fields.PG != 1 ||
Cr0Register.Fields.NE != 1) {
return FALSE;
}
---
CR4_REG Cr4Register = { 0 };
Cr4Register.All = __readcr4();
if (Cr4Register.Fields.VMXE == 1) {
return FALSE;
}
检测操作系统支持 vt 后,就初始化页表,如果有页表随机基址,则搜索随机基址页表,然后保存MTRR,为EPT设置正确的类型
if (!NT_SUCCESS(EptInitializePhysicalMemoryRanges())) {
return STATUS_UNSUCCESSFUL;
}
EptInitializeMtrrEntries();
设置vmcs数据区
// NOTE: Comment in any of those as needed
const ULONG_PTR exception_bitmap =
//1 << kBreakpointException |
// 1 << InterruptionVector::kGeneralProtectionException |
// 1 << kPageFaultException |
0;
VmxBasicMsr.All = UtilReadMsr64(MSR_IA32_VMX_BASIC);
// See: Algorithms for Determining VMX Capabilities
UseTrueMsrs = VmxBasicMsr.Fields.VmxCapabilityHint;
//////////////////////////////////////////////////////////////////////////
// VM - Control
// __vmx_vmlaunch error 7 (VM entry with invalid control field(s)b,c)
//
// Table 24-5. Definitions of Pin-Based VM-Execution Controls
//
VmPinctl.All = VmpAdjustControlValue((UseTrueMsrs) ? MSR_IA32_VMX_TRUE_PINBASED_CTLS
: MSR_IA32_VMX_PINBASED_CTLS,
VmPinctlRequested.All);
Error |= UtilVmWrite(kPinBasedVmExecControl, VmPinctl.All);
//
// 24.6.2 Processor-Based VM-Execution Controls
// 15-bit CR3-load exiting
// 16-bit CR3-store exiting
// 后面 veh 调试要处理 23-bit DR exiting ****
// win10 必须执行对指令 RDTSCP 的支持不然卡死
//
//VmProcctlRequested.Fields.CR3StoreExiting = 1;
//VmProcctlRequested.Fields.MovFrExiting = true;
//vm_procctlRequested.Fields.UseIoBitmaps = true;
//vm_procctlRequested.Fields.UseMsrBitmaps = true;
EPT前置知识,虚拟机的双层地址转换:
这里我们需要将虚拟机内页地址转换为虚拟机物理地址,在转换为真实的物理地址。 这里在构建完成我们的页表后,在 VMX root 模式下修改EPT,所以需要在VMCall 中实现开启 内存隐藏的部分
EnablePageForExecuteOnly(GuestContext->Stack->ProcessorData->EptData, *(ULONG64*)Context);
然后在 EPT表中查找需要找的地址,禁用目标界面的执行,如果当前在 vmx root 模式则需要时 tlb 缓存失效。
Entry = EptGetEptPtEntry(pEptData, GuestPhysicalAddress);
Entry->Fields.ReadAccess = FALSE;
Entry->Fields.ExecuteAccess = TRUE;
Entry->Fields.WriteAccess = FALSE;
Entry->Fields.PhysialAddress = UtilPfnFromPage(MachinePhysicalAddres);
然后在 vmexit 事件中找到 EptViolation(48),检查当前异常是否在我们页面中,然后修改页面,即可完成 ept hook
ULONG64 FaultPhysicalAddress = UtilVmRead64(kGuestPhysicalAddress);
void* FaultVirtualAddress = (void *)( ExitQualification.Fields.ValidGuestLinearAddress? UtilVmRead(kGuestLinearAddress): 0);
if (ExitQualification.Fields.EptReadable ||
ExitQualification.Fields.EptWriteable ||
ExitQualification.Fields.EptExecutable)
{
if (ExitQualification.Fields.CausedByTranslation)
{
BOOLEAN ReadFailure = ExitQualification.Fields.ReadAccess &&
!ExitQualification.Fields.EptReadable;
BOOLEAN WriteFailure = ExitQualification.Fields.WriteAccess &&
!ExitQualification.Fields.EptWriteable;
BOOLEAN ExecuteFailure = ExitQualification.Fields.ExecuteAccess &&
!ExitQualification.Fields.EptExecutable;
if (ReadFailure || WriteFailure|| ExecuteFailure) {
//这里是我们自己设置的
SetHandleEptViolation(Data,EptData, FaultVirtualAddress,(PVOID)FaultPhysicalAddress, ExecuteFailure, WriteFailure, ReadFailure);
}
else {
…………
}
return;
}