ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Intel VT学习笔记(二)—— VMXE&VMXON

2022-02-09 10:06:08  阅读:233  来源: 互联网

标签:Intel unsigned MSR VT VMX VMXON Asm


Intel VT学习笔记(二)—— VMXE&VMXON

VT生命周期

描述:VT生命周期可以参考Intel开发手册第3卷图23-1。
在这里插入图片描述
周壑大大将VT生命周期总结为以下示意图:
在这里插入图片描述
并将这个流程比喻为:

  1. 开锁(将Cr4的VMXE位置1)
  2. 开柜门(VMXON
  3. 拔电源(VMCLEAR,相当于初始化)
  4. 选中机器(VMPTRLOAD,选择需要处理的guest机)
  5. 装机(设置VMCS,通过VMWRITE
  6. 开机(VMLAUNCH
  7. 拔电源(依然是VMCLEAR
  8. 关柜门(VMXOFF
  9. 关锁(将Cr4的VMXE位置0)

VMXE

描述:在进入VMX模式前,需要将Cr4的VMXE位置1,告知他人系统已进入VMX模式,否则会失败。

typedef union
{
	struct{
		unsigned VME:1;
		unsigned PVI:1;
		unsigned TSD:1;
		unsigned DE:1;
		unsigned PSE:1;
		unsigned PAE:1;
		unsigned MCE:1;
		unsigned PGE:1;
		unsigned PCE:1;
		unsigned OSFXSR:1;
		unsigned PSXMMEXCPT:1;
		unsigned UNKONOWN_1:1;		//These are zero
		unsigned UNKONOWN_2:1;		//These are zero
		unsigned VMXE:1;			//It's zero in normal
		unsigned Reserved:18;		//These are zero
		//unsigned Reserved_64:32;
	};
}_CR4;

VMXON

描述:汇编指令,用于进入VMX操作模式。

准备工作

进入VMX模式前的准备工作可参考可参考Intel开发手册第3章31.5小节。
在这里插入图片描述
简单来说,进入VMX模式前需要做的事情有:

  1. 使用CPUID指令查看系统是否支持
  2. 查看相关的MSR寄存器确定VMX支持能力
  3. 创建一个4KB对齐的内存,大小由IA32_VMX_BASIC MSR指定(称作VMXON region)。
  4. 清除申请内存的前四个字节,并设置版本标识符(IA32_VMX_BASIC MSR低4字节)
  5. 确保Cr0PE位、PG位为1
  6. 确保Cr4VMXE位为1
  7. 确保IA32_FEATURE_CONTROL MSR的Lock位为1(BIOS设置)
  8. 以申请内存的物理地址作为操作数,并在执行后检查CF位是否为0

其中,第1、5、6、7点已经学习过,第2点目前来说不重要,先重点关注3、4、8这三点。

VMXON region

描述:在执行VMXON前,需要申请一块内存,用于实现VMX相关功能,例如存储VMM相关信息,由CPU负责维护,这块内存被称为VMXON region。

具体可参考Intel开发手册第3章附录A.1
在这里插入图片描述
这里是说,VMXON region具体大小可从IA32_VMX_BASIC MSR中读取(偏移为480H),第44:32位形成的整数即所需大小。
在这里插入图片描述

申请完内存后,需要将前四个字节设置为版本标识符(第30:0位)
在这里插入图片描述

在进入VMX模式时,需要将这块内存的物理地址作为VMXON的参数,并在执行后检查CF位是否为0。

代码实现

//vtasm.h
#ifndef VTASM_H
#define VTASM_H

typedef union
{
	struct
	{
		unsigned SSE3 : 1;
		unsigned PCLMULQDQ : 1;
		unsigned DTES64 : 1;
		unsigned MONITOR : 1;
		unsigned DS_CPL : 1;
		unsigned VMX : 1;
		unsigned SMX : 1;
		unsigned EIST : 1;
		unsigned TM2 : 1;
		unsigned SSSE3 : 1;
		unsigned Reserved : 22;
	};

}_CPUID_ECX;

typedef struct _IA32_FEATURE_CONTROL_MSR
{
	unsigned Lock : 1;		// Bit 0 is the lock bit - cannot be modified once lock is set
	unsigned Reserved1 : 1;		// Undefined
	unsigned EnableVmxon : 1;		// Bit 2. If this bit is clear, VMXON causes a general protection exception
	unsigned Reserved2 : 29;	// Undefined
	unsigned Reserved3 : 32;	// Undefined

} IA32_FEATURE_CONTROL_MSR;

typedef struct _VMX_BASIC_MSR
{
	unsigned RevId : 32;
	unsigned szVmxOnRegion : 12;
	unsigned ClearBit : 1;
	unsigned Reserved : 3;
	unsigned PhysicalWidth : 1;
	unsigned DualMonitor : 1;
	unsigned MemoryType : 4;
	unsigned VmExitInformation : 1;
	unsigned Reserved2 : 9;
} VMX_BASIC_MSR, * PVMX_BASIC_MSR;

typedef union
{
	struct
	{
		unsigned PE : 1;
		unsigned MP : 1;
		unsigned EM : 1;
		unsigned TS : 1;
		unsigned ET : 1;
		unsigned NE : 1;
		unsigned Reserved_1 : 10;
		unsigned WP : 1;
		unsigned Reserved_2 : 1;
		unsigned AM : 1;
		unsigned Reserved_3 : 10;
		unsigned NW : 1;
		unsigned CD : 1;
		unsigned PG : 1;
		//unsigned Reserved_64:32;
	};

}_CR0;

typedef union
{
	struct {
		unsigned VME : 1;
		unsigned PVI : 1;
		unsigned TSD : 1;
		unsigned DE : 1;
		unsigned PSE : 1;
		unsigned PAE : 1;
		unsigned MCE : 1;
		unsigned PGE : 1;
		unsigned PCE : 1;
		unsigned OSFXSR : 1;
		unsigned PSXMMEXCPT : 1;
		unsigned UNKONOWN_1 : 1;		//These are zero
		unsigned UNKONOWN_2 : 1;		//These are zero
		unsigned VMXE : 1;			//It's zero in normal
		unsigned Reserved : 18;		//These are zero
		//unsigned Reserved_64:32;
	};
}_CR4;

typedef union
{
	struct
	{
		unsigned CF : 1;
		unsigned Unknown_1 : 1;	//Always 1
		unsigned PF : 1;
		unsigned Unknown_2 : 1;	//Always 0
		unsigned AF : 1;
		unsigned Unknown_3 : 1;	//Always 0
		unsigned ZF : 1;
		unsigned SF : 1;
		unsigned TF : 1;
		unsigned IF : 1;
		unsigned DF : 1;
		unsigned OF : 1;
		unsigned TOPL : 2;
		unsigned NT : 1;
		unsigned Unknown_4 : 1;
		unsigned RF : 1;
		unsigned VM : 1;
		unsigned AC : 1;
		unsigned VIF : 1;
		unsigned VIP : 1;
		unsigned ID : 1;
		unsigned Reserved : 10;	//Always 0
		//unsigned Reserved_64:32;	//Always 0
	};
}_EFLAGS;

void Asm_CPUID(ULONG uFn, PULONG uRet_EAX, PULONG uRet_EBX, PULONG uRet_ECX, PULONG uRet_EDX);

ULONG64 Asm_ReadMsr(ULONG uIndex);

ULONG Asm_GetEflags();

ULONG Asm_GetCr0();
ULONG Asm_GetCr4();

void Asm_SetCr4(ULONG uNewCr4);

void Vmx_VmxOn(ULONG LowPart, ULONG HighPart);
void Vmx_VmxOff();

#endif

//vtasm.asm
.686p
.model flat, stdcall
option casemap:none

.data

.code

Asm_CPUID	Proc	uses ebx esi edi fn:dword, ret_eax:dword, ret_ebx:dword, ret_ecx:dword, ret_edx:dword
        mov	eax, fn
        cpuid
        mov	esi, ret_eax
        mov	dword ptr [esi], eax
        mov	esi, ret_ebx
        mov	dword ptr [esi], ebx
        mov	esi, ret_ecx
        mov	dword ptr [esi], ecx
        mov	esi, ret_edx
        mov	dword ptr [esi], edx
        ret
Asm_CPUID 	Endp

Asm_ReadMsr		Proc	Index:dword
        mov	ecx,Index
        rdmsr
        ret
Asm_ReadMsr		Endp

Asm_GetCr0		Proc
        mov 	eax, cr0
        ret
Asm_GetCr0 		Endp

Asm_GetCr4		Proc
        mov 	eax, cr4
        ret
Asm_GetCr4 		Endp

Asm_SetCr4		Proc	NewCr4:dword
        mov 	eax,NewCr4
        mov 	cr4, eax
        ret
Asm_SetCr4 		Endp

Vmx_VmxOn Proc LowPart:dword,HighPart:dword
        push HighPart
        push LowPart
        Vmxon qword ptr [esp]
        add esp,8
        ret
Vmx_VmxOn Endp

Vmx_VmxOff Proc
        Vmxoff
        ret
Vmx_VmxOff Endp

Asm_GetEflags PROC
        pushfd
        pop		eax
        ret
Asm_GetEflags ENDP

END
//vtsystem.h
#ifndef VTSYSTEM_H
#define VTSYSTEM_H
#include <ntddk.h>

/*MSR definition*/
#define MSR_IA32_FEATURE_CONTROL 		0x03a
#define MSR_IA32_VMX_BASIC              0x480

typedef struct _VMX_CPU
{
    PVOID               pVMXONRegion;
    PHYSICAL_ADDRESS    pVMXONRegion_PA;
    PVOID               pVMCSRegion;
    PHYSICAL_ADDRESS    pVMCSRegion_PA;
    PVOID               pStack;

    BOOLEAN             bVTStartSuccess;
}VMX_CPU, * PVMX_CPU;

//检查当前处理器是否支持VT
BOOLEAN IsVTEnabled();
//开启VT
NTSTATUS StartVirtualTechnology();
//关闭VT
NTSTATUS StopVirtualTechnology();

#define Log(message,value) {{KdPrint(("[MinVT] %-40s [%p]\n",message,value));}}

#endif
//vtsystem.c
#include "vtsystem.h"
#include "vtasm.h"

VMX_CPU g_VMXCPU;

BOOLEAN IsVTEnabled()
{
    ULONG       uRet_EAX, uRet_ECX, uRet_EDX, uRet_EBX;
    _CPUID_ECX  uCPUID;
    _CR0        uCr0;
    _CR4    uCr4;
    IA32_FEATURE_CONTROL_MSR msr;
    //1. CPUID
    Asm_CPUID(1, &uRet_EAX, &uRet_EBX, &uRet_ECX, &uRet_EDX);
    *((PULONG)&uCPUID) = uRet_ECX;

    if (uCPUID.VMX != 1)
    {
        Log("ERROR: 这个CPU不支持VT!", 0);
        return FALSE;
    }

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

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

    if (uCr0.PE != 1 || uCr0.PG != 1 || uCr0.NE != 1)
    {
        Log("ERROR:这个CPU没有开启VT!", 0);
        return FALSE;
    }

    if (uCr4.VMXE == 1)
    {
        Log("ERROR:这个CPU已经开启了VT!", 0);
        Log("可能是别的驱动已经占用了VT,你必须关闭它后才能开启。", 0);
        return FALSE;
    }

    Log("SUCCESS:这个CPU支持VT!", 0);
    return TRUE;
}

NTSTATUS StartVirtualTechnology()
{
    PVOID pVMXONRegion;
    VMX_BASIC_MSR Msr;
    ULONG uRevId;
    _CR4 uCr4;
    _EFLAGS uEflags;

    if (!IsVTEnabled())
        return STATUS_NOT_SUPPORTED;

    *((PULONG)&uCr4) = Asm_GetCr4();		//设置Cr4的VMXE位
    uCr4.VMXE = 1;
    Asm_SetCr4(*((PULONG)&uCr4));

    pVMXONRegion = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'vmon'); //申请一块4KB内存,给VMM用
    if (!pVMXONRegion)
    {
        Log("ERROR:申请VMXON内存区域失败!", 0);
        return STATUS_MEMORY_NOT_ALLOCATED;
    }
    RtlZeroMemory(pVMXONRegion, 0x1000);

    g_VMXCPU.pVMXONRegion = pVMXONRegion;
    g_VMXCPU.pVMXONRegion_PA = MmGetPhysicalAddress(pVMXONRegion);	//获得这块内存的物理地址

    *((PULONG)&Msr) = (ULONG)Asm_ReadMsr(MSR_IA32_VMX_BASIC);
    uRevId = Msr.RevId;

    Log("TIP:VMX版本号信息", uRevId);

    *((PULONG)g_VMXCPU.pVMXONRegion) = uRevId;		//设置版本标识符

	//将64位物理地址作为VMXON参数,执行
    Vmx_VmxOn(g_VMXCPU.pVMXONRegion_PA.LowPart, g_VMXCPU.pVMXONRegion_PA.HighPart);	

    *((PULONG)&uEflags) = Asm_GetEflags();
    if (uEflags.CF != 0)		//通过CF位判断是否调用成功
    {
        Log("ERROR:VMXON指令调用失败!", 0);
        return STATUS_UNSUCCESSFUL;
    }

    Log("SUCCESS:VMXON指令调用成功!", 0);

    return STATUS_SUCCESS;
}

NTSTATUS StopVirtualTechnology()
{
    _CR4 uCr4;
    
    Vmx_VmxOff();	//退出VMX模式
    
    *((PULONG)&uCr4) = Asm_GetCr4();		//设置VMXE为0
    uCr4.VMXE = 0;
    Asm_SetCr4(*((PULONG)&uCr4));

    ExFreePool(g_VMXCPU.pVMXONRegion);		//释放内存

    Log("SUCCESS:VMXOFF指令调用成功!", 0);

    return STATUS_SUCCESS;
}
//driver.c
#include <ntddk.h>
#include "vtasm.h"
#include "vtsystem.h"

VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	StopVirtualTechnology();
	DbgPrint("Driver unload. \r\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
	DbgPrint("Driver load. \r\n");

	StartVirtualTechnology();

	pDriver->DriverUnload = DriverUnload;

	return STATUS_SUCCESS;
}

执行结果:
在这里插入图片描述

参考资料

标签:Intel,unsigned,MSR,VT,VMX,VMXON,Asm
来源: https://blog.csdn.net/qq_41988448/article/details/122791042

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有