1 vt整体框架;

首先 开锁:

1 开启 Cr4.[VMXE]:

上一节,检测了 VMX 需要的环境;最后一个 CR4.[13/VMXE] 只检测了是否已经被开启(有别的虚拟机);

但是 没有在 CR4.[13/VMXE] ==0 的时候去开启。

所以 这里 开始 开锁;打开 CR4.[13]

放在 驱动加载函数中。

  • 代码:

    NTSTATUS StartVirtualTechnology()

    {
    _CR4 uCr4;
    if(!IsVTEnabled())
    {
    return STATUS_UNSUCCESSFUL;
    }
    *((PULONG)&uCr4) = Asm_GetCr4();// 获取原来的 cr4;
    uCr4.VMXE =1;// VMXE =1 开启。
    Asm_SetCr4(*(PULONG)&uCr4); // 设置回去

    return STATUS_SUCCESS;
    }

2开始 进入 VMXON:

接下来的最简流程:(参考白皮书 3卷31.5节)

这里 红色部分是需要实现的部分:

最后 关锁:

1 关闭 VMXOFF:

2 恢复 CR4.[VMXE]:

设置 CR4.[13/VMXE] ==0 的时候关闭;

放在驱动卸载函数中

  • 代码:

    NTSTATUS StopVirtualTechnology()

    {
    _CR4 uCr4;

    Vmx_VmxOff();

    *((PULONG)&uCr4) = Asm_GetCr4();// get cr4;
    uCr4.VMXE =0;// VMXE =0 disable
    Asm_SetCr4(*(PULONG)&uCr4); // set;

    // free page; in kernel nonpage its not freed automatic;
    ExFreePool(g_VMXCPU.pVMXONRegion);


    return  STATUS_SUCCESS;
    }

初步效果:

整体代码:

.cpp(开启 、关闭 VMX的函数实现)

#include "stdafx.h"



VMX_CPU g_VMXCPU;

BOOLEAN IsVTEnabled()
{
ULONG uRet_EAX, uRet_RCX,uRet_EDX,uRet_EBX;
_CPUID_ECX uCPUID;
_CR0  uCr0;
_CR4  uCr4;
IA32_FEATURE_CONTROL_MSR msr;

// 1. check CPUID .[5] VMXON is enabled?
Asm_CPUID(1,&uRet_EAX,&uRet_EBX,&uRet_RCX,&uRet_EDX); // eax-->1 ; cpuid; check retRegValues;
*((PULONG)&uCPUID) = uRet_RCX;
if(uCPUID.VMX !=1)
{
Log("ERROR:当前 CPU 不支持VT",0);
return FALSE;
}

// 2. check MSR 3ah 
*((PULONG)&msr) = (ULONG) Asm_ReadMsr(MSR_IA32_FEATURE_CONTROL);// 0x3ah
if(msr.Lock!=1)
{
Log("ERROR:VT 指令未被锁定",0);
return FALSE;
}

// 3. check CR0\CR4
*((PULONG)&uCr0) = Asm_GetCr0();
*((PULONG)&uCr4) = Asm_GetCr4();

if(uCr0.PE!=1 || uCr0.PG!=1 || uCr0.NE!=1)
{
Log("ERROR:这个CPU 所处的环境不是页保护模式",0);
return FALSE;
}
if(uCr4.VMXE ==1)
{
Log("ERROR:这个CPU 已经开启了VT,可能有别的驱动占用;请检查关闭再试!",0);
return FALSE;

}
else
{

}
Log("Checked, the Env is Prepared!",0);
return TRUE;
}

NTSTATUS StartVirtualTechnology()
{
_CR4 uCr4;
_EFLAGS uEflags;
if(!IsVTEnabled())
{
return STATUS_UNSUCCESSFUL;
}
*((PULONG)&uCr4) = Asm_GetCr4();//get cr4;
uCr4.VMXE =1;// VMXE =1 enable
Asm_SetCr4(*(PULONG)&uCr4); // set

g_VMXCPU.pVMXONRegion = ExAllocatePoolWithTag(NonPagedPool,0x1000,'vmx');// para@3 is digit value
RtlZeroMemory(g_VMXCPU.pVMXONRegion,0x1000);// initial memory
*(PULONG)g_VMXCPU.pVMXONRegion =1;//set revision; -- the first 32bits of VMXONRegion; clear the no.32bit
g_VMXCPU.pVMXONRegion_PA = MmGetPhysicalAddress(g_VMXCPU.pVMXONRegion);// get physical address


Vmx_VmxOn(g_VMXCPU.pVMXONRegion_PA.LowPart,g_VMXCPU.pVMXONRegion_PA.HighPart);
*((PULONG)&uEflags) = Asm_GetEflags();

if(uEflags.CF!=0)// the flag to identify state of success or not
{
Log("ERROR:VMXON指令调用失败!",0);
ExFreePool(g_VMXCPU.pVMXONRegion);
return STATUS_UNSUCCESSFUL;
}

return STATUS_SUCCESS;
}

NTSTATUS StopVirtualTechnology()
{
_CR4 uCr4;

Vmx_VmxOff();

*((PULONG)&uCr4) = Asm_GetCr4();// get cr4;
uCr4.VMXE =0;// VMXE =0 disable
Asm_SetCr4(*(PULONG)&uCr4); // set;

// free page; in kernel nonpage its not freed automatic;
ExFreePool(g_VMXCPU.pVMXONRegion);


return  STATUS_SUCCESS;

}

.c (驱动文件,调用VMX开启关闭函数)

#include "stdafx.h"


EXTERN_C void Asm_xx();
EXTERN_C BOOLEAN IsVTEnabled();
EXTERN_C NTSTATUS StartVirtualTechnology();
EXTERN_C NTSTATUS StopVirtualTechnology();
VOID DriverUnLoad(PDRIVER_OBJECT driver)
{

StopVirtualTechnology();
DbgPrint("VT stopping ....!\r\n");
DbgPrint("Driver is unloading...r\n");
}
NTSTATUS DriverEntry(
PDRIVER_OBJECT driver ,
PUNICODE_STRING RegistryPath)
{
Asm_xx();
DbgPrint("Driver Entered!\r\n");
StartVirtualTechnology();
DbgPrint("VT running....!\r\n");
driver->DriverUnload = DriverUnLoad;
return STATUS_SUCCESS;
}


感谢 周壑老师的讲解

01-25 16:57