zhouhe VT(四) _VMCS

vmxon到vmlaunch期间

一、为每个虚拟机分配4kb大小空间

Intel手册第三卷31.6
0
 
在VMX功能MSR IA32_VMX_BASIC指定的大小的非分页内存中创建一个VMCS区域,对齐为4 kb
把前31位初始化为版本号,清除前四个字节的第31位

二、vmclear

0
通过提供的guest-VMCS地址来执行VMCLEAR
vmclear 通过检测EFLAG.cf位与EFLAG.ZF位来判断vmclear是否正确执行
 

三、VMPTRLD

0
通过提供的guest-VMCS地址来执行VMPTRLD
这将使用新的VMCS区域的物理地址初始化工作VMCS指针

四、VMWRITE

0
发出一个vmwrite序列来初始化工作的VMCS中的各个主机状态区域字段,初始化将在后续VM退出客户机时设置VMM的上下文和入口点。主机状态字段包括控制寄存器(CRO, CR3和CR4),段寄存器(CS, SS, DS, ES, FS, GS和TR)的选择器字段,和基址字段(FS, GS, TR, GDTR和IDTR;RSP、RIP和控制快速系统调用的msr)
 
0
使用vmwrite在VMCS中设置虚拟机退出控制字段、虚拟机进入控制字段和虚拟机执行控制字段。应该注意确保各个字段的设置与VMX能力msr报告的相应控件允许的O和1设置相匹配(见附录A)。任何与能力msr报告的设置不一致的设置将导致VM条目失败。
 
0
使用VMWRITE在工作的VMCS中初始化各种来宾状态区域字段。这将在VM入口时为来宾执行设置上下文和入口点。第27章描述了客户机状态的加载和处理器对VM条目进行的检查,以保护和执行virtual-8086客户机
 

五、VMLAUNCH

0
执行vmlaunch后,通过检查EFLAG寄存器的ZF位或CF位来检测是否运行成功,
VM-instruction错误字段将会包含错误代码
 
 

六、VMCSs的概念(附)

VMCSs:virtual-machine control data structures虚拟机控制结构
Intel手册第三卷24.1
0
逻辑处理器在VMX操作时使用虚拟机控制数据结构(VMCSs)。它们管理进入和退出VMX非root操作(虚拟机入口和虚拟机出口),以及VMX非root操作中的处理器行为。这个结构由新的指令VMCLEAR、VMPTRLD、VMREAD和VMWRITE操作。
每个guest对应一个这样的结构
 

七、VMX的root与no-root的概念(附)

0
处理器对虚拟化的支持是通过一种称为VMX操作的处理器操作形式提供的。VMX操作有两种:VMX根操作和VMX非根操作。通常,VMM将在VMX根操作中运行,而客户软件将在VMX非根操作中运行。
VMX根操作和VMX非根操作之间的转换称为VMX转换。VMX转换有两种。过渡到VMX非根操作称为VM条目。从VMX的非根操作过渡到VMX的根操作称为虚拟机退出。
VMX根操作中的处理器行为与VMX操作之外的处理器行为非常相似。主要的区别是一组新的指令(VMX指令)是可用的,并且可以加载到某些控制寄存器的值是有限的(参见第23.8节)。
VMX非根操作中的处理器行为受到限制和修改,以促进虚拟化。
0
VMX非根操作和VMX转换由一种称为虚拟机控制结构(VMCS)的数据结构控制。
通过称为VMCS指针(每个逻辑处理器一个)的处理器状态组件来管理对VMCS的访问。VMCS指针的值为该VMCS的64位地址。VMCS指针的读写使用VMPTRST和VMPTRLD指令。
VMM通过VMREAD、VMWRITE和VMCLEAR指令配置VMCS。
VMM可以为它支持的每个虚拟机使用不同的vmcs。对于具有多个逻辑处理器(虚拟处理器)的虚拟机,VMM可以为每个虚拟处理器使用不同的VMCS。
 
 

八、执行失败返回的错误号

 
0
 
解决错误号为7的control错误
vm control fields vm控制域:

九、vm execution control

1、Pin-Based

0
0
基于pin的虚拟机执行控制构成了一个32位的向量,该字段中所有其他的位都被保留,一些为0,一些为1。软件应该参考VMX能力MSRs ia32_vmx_pinbased_ctl和ia32_vmx_true_pinbased_ctl来确定如何设置预留位。如果预留位设置不正确,将导致后续的虚拟机表项失败
 
A.3.1中介绍了MSR寄存器 ia32_vmx_pinbased_ctl,它是下标为481h的控制寄存器
0
 
它的后32位决定了32位向量必须置1的位,前32位决定了32位向量必须置0的位
0
必须置1的位:1.2.4
 

2、Processor-Based

一些必须设置的位依赖于IA32_VMX_PROCBASED_CTLS msr寄存器
0
0
 
1,4,5,6,7,13,14,15,16,26位必须设为1
0
也就是说读写CR3的时候必须退出虚拟机
 
其他的位我们也可以自己去设置,如第23位的调试域...
再如第28位,如果我们把这一位设置为0,虚拟机里的MSR寄存器都为0,如果虚拟机想要操作MSR寄存器的话,就要被宿主机拦截
0
 

十、vm exit control

24.7.1
0
依赖于IA32_VMX_EXIT_CTLS寄存器
0
下表为483的msr寄存器

十一、vm entry control

0
0
依赖于IA32_VMX_ENTRY_CTLS寄存器,这是下标为484的msr寄存器
0
 
 
解决错误号为8的host错误
Host state fields 主机状态域 它决定了虚拟机中断或发生异常怎样返回Host或 返回Host的哪个地址

十二、HOST-STATE AREA 

24.5
0
我们需要在虚拟机中向这些寄存器中添值
 
如CR0 CR3 CR4寄存器,RSP,RIP,寄存器,各种段选择子(除了LDTR)
FS,GS,TR,GDTR,IDTR段寄存器的基址
CS,ESP,EIP寄存器的值
 
0
这里需要 & 0xfff8的原因是,切换成0环段选择子
 ...目前用到的代码文件

 主要代码:

vtsystem.c:

#include "vtsystem.h" #include "vtasm.h" #include "exithandler.h" VMX_CPU g_VMXCPU; static ULONG VmxAdjustControls(ULONG Ctl, ULONG Msr) { LARGE_INTEGER MsrValue; MsrValue.QuadPart = Asm_ReadMsr(Msr); Ctl &= MsrValue.HighPart; /* bit == 0 in high word ==> must be zero */ Ctl |= MsrValue.LowPart; /* bit == 1 in low word ==> must be one */ return Ctl; } void SetupVMCS() { ULONG GdtBase, IdtBase; GdtBase = Asm_GetGdtBase(); IdtBase = Asm_GetIdtBase(); //1、Guest state fields //2、Host state fields Vmx_VmWrite(HOST_CR0, Asm_GetCr0()); Vmx_VmWrite(HOST_CR3, Asm_GetCr3()); Vmx_VmWrite(HOST_CR4, Asm_GetCr4()); Vmx_VmWrite(HOST_ES_SELECTOR, Asm_GetEs() & 0xFFF8); //调成0环的段选择子// Vmx_VmWrite(HOST_CS_SELECTOR, Asm_GetCs() & 0xFFF8); Vmx_VmWrite(HOST_DS_SELECTOR, Asm_GetDs() & 0xFFF8); Vmx_VmWrite(HOST_FS_SELECTOR, Asm_GetFs() & 0xFFF8); Vmx_VmWrite(HOST_GS_SELECTOR, Asm_GetGs() & 0xFFF8); Vmx_VmWrite(HOST_SS_SELECTOR, Asm_GetSs() & 0xFFF8); Vmx_VmWrite(HOST_TR_SELECTOR, Asm_GetTr() & 0xFFF8); Vmx_VmWrite(HOST_TR_BASE, 0x80042000); //tr寄存器在5号段选择子上,直接查,为0x80042000// 直接填充为tr的基地址// Vmx_VmWrite(HOST_GDTR_BASE, GdtBase); Vmx_VmWrite(HOST_IDTR_BASE, IdtBase); Vmx_VmWrite(HOST_IA32_SYSENTER_CS, Asm_ReadMsr(MSR_IA32_SYSENTER_CS) & 0xFFFFFFFF); Vmx_VmWrite(HOST_IA32_SYSENTER_ESP, Asm_ReadMsr(MSR_IA32_SYSENTER_ESP) & 0xFFFFFFFF); Vmx_VmWrite(HOST_IA32_SYSENTER_EIP, Asm_ReadMsr(MSR_IA32_SYSENTER_EIP) & 0xFFFFFFFF); // KiFastCallEntry Vmx_VmWrite(HOST_RSP, ((ULONG)g_VMXCPU.pStack) + 0x1000); //Host 临时栈 //为后面的中断单独分配一个栈,防止线程切换的时候影响到后续程序的执行// 栈顶 Vmx_VmWrite(HOST_RIP, (ULONG)VMMEntryPoint); //这里定义我们的VMM处理程序入口 //3、vm-control fields // 3.1、vm execution control Vmx_VmWrite(PIN_BASED_VM_EXEC_CONTROL, VmxAdjustControls(0, MSR_IA32_VMX_PINBASED_CTLS)); Vmx_VmWrite(CPU_BASED_VM_EXEC_CONTROL, VmxAdjustControls(0, MSR_IA32_VMX_PROCBASED_CTLS)); // 3.2、vm exit control Vmx_VmWrite(VM_EXIT_CONTROLS, VmxAdjustControls(0, MSR_IA32_VMX_EXIT_CTLS)); // 3.3、vm entry control Vmx_VmWrite(VM_ENTRY_CONTROLS, VmxAdjustControls(0, MSR_IA32_VMX_ENTRY_CTLS)); } NTSTATUS StartVirtualTechnology() { _CR4 uCr4; _EFLAGS uEflags; if(!IsVTEnabled()) { return STATUS_UNSUCCESSFUL; } *((PULONG)&uCr4) = Asm_GetCr4(); uCr4.VMXE = 1; //第一步,开锁完成// Asm_SetCr4(*((PULONG)&uCr4)); g_VMXCPU.pVMXONRegion = ExAllocatePoolWithTag(NonPagedPool,0x1000,'tlsn');//最多分配4k,还要满足4k大小对齐//那这里直接分配4k// RtlZeroMemory(g_VMXCPU.pVMXONRegion, 0x1000); *(PULONG)g_VMXCPU.pVMXONRegion = 1;// // g_VMXCPU.pVMXONRegion_PA = MmGetPhysicalAddress(g_VMXCPU.pVMXONRegion);//virtual add to phy add// Vmx_VmxOn(g_VMXCPU.pVMXONRegion_PA.LowPart,g_VMXCPU.pVMXONRegion_PA.HighPart);//第二步,开启VmxOn模式// *((PULONG)&uEflags) = Asm_GetEflags(); if(uEflags.CF != 0) { Log("Error: VMXON指令调用失败!", 0); ExFreePool(g_VMXCPU.pVMXONRegion); return STATUS_UNSUCCESSFUL; } Log("vmcon success", 0); //为虚拟机分配4kb// g_VMXCPU.pVMCSRegion = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'vmcs');//最多分配4k,还要满足4k大小对齐//那这里直接分配4k// RtlZeroMemory(g_VMXCPU.pVMCSRegion, 0x1000); *(PULONG)g_VMXCPU.pVMCSRegion = 1;// g_VMXCPU.pVMCSRegion_PA = MmGetPhysicalAddress(g_VMXCPU.pVMCSRegion);//virtual add to phy add// Vmx_VmClear(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart); //第三步拔电源// //第四步,选中机器 (我们可能有很多虚拟机,我们要进行选择)// Vmx_VmPtrld(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart); g_VMXCPU.pStack = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'stck'); //// RtlZeroMemory(g_VMXCPU.pVMCSRegion, 0x1000); Log("host_stack: ", g_VMXCPU.pStack); //第五步,设置vmcs(vmwrite) ,装机//设置大量寄存器信息// SetupVMCS(); //第六步... Vmx_VmLaunch(); //执行成功,直接跳走,不再向下执行,执行失败,EFLAG的CF或ZF位置1// VM - instruction错误字段将会包含错误代码// Log("ERROR: VmLaunch指令调用失败!!!!!!",Vmx_VmRead(VM_INSTRUCTION_ERROR)); //从错误字段中读取错误号// Intel第三卷 30-4中可以查看错误号// return STATUS_SUCCESS; } NTSTATUS StopVirtualTechnology() { _CR4 uCr4; Vmx_VmxOff(); //关柜门 *((PULONG)&uCr4) = Asm_GetCr4(); uCr4.VMXE = 0; //关锁// Asm_SetCr4(*((PULONG)&uCr4)); ExFreePool(g_VMXCPU.pVMXONRegion);//在内核分配的内存需要我们自己手动释放// DbgPrint("VT Stop"); return STATUS_SUCCESS; } BOOLEAN IsVTEnabled() //判断主机能不能开启vt// { 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; }

 

阶段实验:

完美断下
 
 

十三、Guest state fields

上图的实验会报 0x80000012错误

1、错误号的查看

24.9.1
0
如我们的错误码第31位为1,说明VM进入失败

2、设置寄存器

Intel 第三卷24.4
0
 
加载寄存器信息的方法我都写到了代码中
代码如下
vtsystem.c
#include "vtsystem.h" #include "vtasm.h" #include "exithandler.h" VMX_CPU g_VMXCPU; static ULONG VmxAdjustControls(ULONG Ctl, ULONG Msr) { LARGE_INTEGER MsrValue; MsrValue.QuadPart = Asm_ReadMsr(Msr); Ctl &= MsrValue.HighPart; /* bit == 0 in high word ==> must be zero */ Ctl |= MsrValue.LowPart; /* bit == 1 in low word ==> must be one */ return Ctl; } void __declspec(naked) GuestEntry() //guest入口// { //加载段选择子与基址// __asm { mov ax, es mov es, ax mov ax, ds mov ds, ax mov ax, fs mov fs, ax mov ax, gs mov gs, ax mov ax, ss mov ss, ax } Vmx_VmCall();//vmcall功能就是回到host// } void SetupVMCS() { ULONG GdtBase, IdtBase; GdtBase = Asm_GetGdtBase(); IdtBase = Asm_GetIdtBase(); //1、Guest state fields Vmx_VmWrite(GUEST_CR0, Asm_GetCr0()); Vmx_VmWrite(GUEST_CR3, Asm_GetCr3()); Vmx_VmWrite(GUEST_CR4, Asm_GetCr4()); Vmx_VmWrite(GUEST_DR7, 0x400);//Dr7调试寄存器默认就是0x400// Vmx_VmWrite(GUEST_RFLAGS, Asm_GetEflags() & ~0x200); //eflag寄存器关中断//cli Vmx_VmWrite(GUEST_ES_SELECTOR, Asm_GetEs() & 0xFFF8); Vmx_VmWrite(GUEST_CS_SELECTOR, Asm_GetCs() & 0xFFF8); Vmx_VmWrite(GUEST_DS_SELECTOR, Asm_GetDs() & 0xFFF8); Vmx_VmWrite(GUEST_FS_SELECTOR, Asm_GetFs() & 0xFFF8); Vmx_VmWrite(GUEST_GS_SELECTOR, Asm_GetGs() & 0xFFF8); Vmx_VmWrite(GUEST_SS_SELECTOR, Asm_GetSs() & 0xFFF8); Vmx_VmWrite(GUEST_TR_SELECTOR, Asm_GetTr() & 0xFFF8); Vmx_VmWrite(GUEST_ES_AR_BYTES, 0x10000); //Intel手册第三卷 Table 24-2 把这些段选择子设为不可用的段选择子需要第16位置1// Vmx_VmWrite(GUEST_FS_AR_BYTES, 0x10000); //防止CPU当作可用,而加载错误的属性// Vmx_VmWrite(GUEST_DS_AR_BYTES, 0x10000); //防止CPU当作可用,而加载错误的属性// Vmx_VmWrite(GUEST_SS_AR_BYTES, 0x10000); //防止CPU当作可用,而加载错误的属性// Vmx_VmWrite(GUEST_GS_AR_BYTES, 0x10000); //防止CPU当作可用,而加载错误的属性// Vmx_VmWrite(GUEST_LDTR_AR_BYTES, 0x10000); //防止CPU当作可用,而加载错误的属性// Vmx_VmWrite(GUEST_CS_AR_BYTES, 0xc09b); //直接读的1号段描述符// Vmx_VmWrite(GUEST_CS_BASE, 0); Vmx_VmWrite(GUEST_CS_LIMIT, 0xffffffff); Vmx_VmWrite(GUEST_TR_AR_BYTES, 0x008b); //5号// Vmx_VmWrite(GUEST_TR_BASE, 0x80042000); Vmx_VmWrite(GUEST_TR_LIMIT, 0x20ab); Vmx_VmWrite(GUEST_GDTR_BASE, GdtBase); Vmx_VmWrite(GUEST_GDTR_LIMIT, Asm_GetGdtLimit()); Vmx_VmWrite(GUEST_IDTR_BASE, IdtBase); Vmx_VmWrite(GUEST_IDTR_LIMIT, Asm_GetIdtLimit()); //Vmx_VmWrite(GUEST_IA32_DEBUGCTL, Asm_ReadMsr(MSR_IA32_DEBUGCTL) & 0xFFFFFFFF); //Vmx_VmWrite(GUEST_IA32_DEBUGCTL_HIGH, Asm_ReadMsr(MSR_IA32_DEBUGCTL) >> 32); Vmx_VmWrite(GUEST_SYSENTER_CS, Asm_ReadMsr(MSR_IA32_SYSENTER_CS) & 0xFFFFFFFF); Vmx_VmWrite(GUEST_SYSENTER_ESP, Asm_ReadMsr(MSR_IA32_SYSENTER_ESP) & 0xFFFFFFFF); Vmx_VmWrite(GUEST_SYSENTER_EIP, Asm_ReadMsr(MSR_IA32_SYSENTER_EIP) & 0xFFFFFFFF); // KiFastCallEntry Vmx_VmWrite(GUEST_RSP, ((ULONG)g_VMXCPU.pStack) + 0x1000); //Guest 临时栈 //上半4kb给guest使用// Vmx_VmWrite(GUEST_RIP, (ULONG)GuestEntry); // 客户机的入口点 Vmx_VmWrite(VMCS_LINK_POINTER, 0xffffffff); //不使用shadow vmcs,都置成f// Vmx_VmWrite(VMCS_LINK_POINTER_HIGH, 0xffffffff); //不使用shadow vmcs,都置成f// //2、Host state fields Vmx_VmWrite(HOST_CR0, Asm_GetCr0()); Vmx_VmWrite(HOST_CR3, Asm_GetCr3()); Vmx_VmWrite(HOST_CR4, Asm_GetCr4()); Vmx_VmWrite(HOST_ES_SELECTOR, Asm_GetEs() & 0xFFF8); //Intel规定后三位必须为0// Vmx_VmWrite(HOST_CS_SELECTOR, Asm_GetCs() & 0xFFF8); Vmx_VmWrite(HOST_DS_SELECTOR, Asm_GetDs() & 0xFFF8); Vmx_VmWrite(HOST_FS_SELECTOR, Asm_GetFs() & 0xFFF8); Vmx_VmWrite(HOST_GS_SELECTOR, Asm_GetGs() & 0xFFF8); Vmx_VmWrite(HOST_SS_SELECTOR, Asm_GetSs() & 0xFFF8); Vmx_VmWrite(HOST_TR_SELECTOR, Asm_GetTr() & 0xFFF8); Vmx_VmWrite(HOST_TR_BASE, 0x80042000); //tr寄存器在5号段选择子上,直接查,为0x80042000// 直接填充为tr的基地址// Vmx_VmWrite(HOST_GDTR_BASE, GdtBase); Vmx_VmWrite(HOST_IDTR_BASE, IdtBase); Vmx_VmWrite(HOST_IA32_SYSENTER_CS, Asm_ReadMsr(MSR_IA32_SYSENTER_CS) & 0xFFFFFFFF); Vmx_VmWrite(HOST_IA32_SYSENTER_ESP, Asm_ReadMsr(MSR_IA32_SYSENTER_ESP) & 0xFFFFFFFF); Vmx_VmWrite(HOST_IA32_SYSENTER_EIP, Asm_ReadMsr(MSR_IA32_SYSENTER_EIP) & 0xFFFFFFFF); // KiFastCallEntry Vmx_VmWrite(HOST_RSP, ((ULONG)g_VMXCPU.pStack) + 0x2000); //Host 临时栈 //为后面的中断单独分配一个栈,防止线程切换的时候影响到后续程序的执行// 栈顶 Vmx_VmWrite(HOST_RIP, (ULONG)VMMEntryPoint); //这里定义我们的VMM处理程序入口 //3、vm-control fields // 3.1、vm execution control Vmx_VmWrite(PIN_BASED_VM_EXEC_CONTROL, VmxAdjustControls(0, MSR_IA32_VMX_PINBASED_CTLS)); Vmx_VmWrite(CPU_BASED_VM_EXEC_CONTROL, VmxAdjustControls(0, MSR_IA32_VMX_PROCBASED_CTLS)); // 3.2、vm exit control Vmx_VmWrite(VM_EXIT_CONTROLS, VmxAdjustControls(0, MSR_IA32_VMX_EXIT_CTLS)); // 3.3、vm entry control Vmx_VmWrite(VM_ENTRY_CONTROLS, VmxAdjustControls(0, MSR_IA32_VMX_ENTRY_CTLS)); } NTSTATUS StartVirtualTechnology() { _CR4 uCr4; _EFLAGS uEflags; if(!IsVTEnabled()) { return STATUS_UNSUCCESSFUL; } *((PULONG)&uCr4) = Asm_GetCr4(); uCr4.VMXE = 1; //第一步,开锁完成// Asm_SetCr4(*((PULONG)&uCr4)); g_VMXCPU.pVMXONRegion = ExAllocatePoolWithTag(NonPagedPool,0x1000,'tlsn');//最多分配4k,还要满足4k大小对齐//那这里直接分配4k// RtlZeroMemory(g_VMXCPU.pVMXONRegion, 0x1000); *(PULONG)g_VMXCPU.pVMXONRegion = 1;// // g_VMXCPU.pVMXONRegion_PA = MmGetPhysicalAddress(g_VMXCPU.pVMXONRegion);//virtual add to phy add// Vmx_VmxOn(g_VMXCPU.pVMXONRegion_PA.LowPart,g_VMXCPU.pVMXONRegion_PA.HighPart);//第二步,开启VmxOn模式// *((PULONG)&uEflags) = Asm_GetEflags(); if(uEflags.CF != 0) { Log("Error: VMXON指令调用失败!", 0); ExFreePool(g_VMXCPU.pVMXONRegion); return STATUS_UNSUCCESSFUL; } Log("vmcon success", 0); //为虚拟机分配4kb// g_VMXCPU.pVMCSRegion = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'vmcs');//最多分配4k,还要满足4k大小对齐//那这里直接分配4k// RtlZeroMemory(g_VMXCPU.pVMCSRegion, 0x1000); *(PULONG)g_VMXCPU.pVMCSRegion = 1;// g_VMXCPU.pVMCSRegion_PA = MmGetPhysicalAddress(g_VMXCPU.pVMCSRegion);//virtual add to phy add// Vmx_VmClear(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart); //第三步拔电源// //第四步,选中机器 (我们可能有很多虚拟机,我们要进行选择)// Vmx_VmPtrld(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart); g_VMXCPU.pStack = ExAllocatePoolWithTag(NonPagedPool, 0x2000, 'stck'); //// RtlZeroMemory(g_VMXCPU.pVMCSRegion, 0x2000); Log("host_stack: ", g_VMXCPU.pStack); //第五步,设置vmcs(vmwrite) ,装机//设置大量寄存器信息// SetupVMCS(); //第六步... Vmx_VmLaunch(); //执行成功,直接跳走,不再向下执行,执行失败,EFLAG的CF或ZF位置1// VM - instruction错误字段将会包含错误代码// Log("ERROR: VmLaunch指令调用失败!!!!!!",Vmx_VmRead(VM_INSTRUCTION_ERROR)); //从错误字段中读取错误号// Intel第三卷 30-4中可以查看错误号// return STATUS_SUCCESS; } NTSTATUS StopVirtualTechnology() { _CR4 uCr4; Vmx_VmxOff(); //关柜门 *((PULONG)&uCr4) = Asm_GetCr4(); uCr4.VMXE = 0; //关锁// Asm_SetCr4(*((PULONG)&uCr4)); ExFreePool(g_VMXCPU.pVMXONRegion);//在内核分配的内存需要我们自己手动释放// DbgPrint("VT Stop"); return STATUS_SUCCESS; } BOOLEAN IsVTEnabled() //判断主机能不能开启vt// { 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; }

 

实验

0
我们u一下guest的eip
0
可以发现guest还停止vmcall的位置
 
另外,之前报0x80000012错误通过处理Guest state fields已经解决了第31位进入VM失败的错误,现在虽然任然有错误,但已经不是进入虚拟机错误了...
 
 
 

十四、VMCS SHADOW的概念(附)

24.10
0
 

小总结

1、我们还需要为虚拟机分配最大为4kb,且4kb大小对齐的非分页内存,同时满足前四个字节为版本号
2、Wmx_VmClear
3、Vmx_VmPtrld选中机器
4、Vmx_VmLaunch装机
(1)、Guest state fields
(2)、Host state fields
(3)、vm-control fields
      (3.1)vm execution control
   (3.2)vm exit control
   (3.3)vm entry control
 

参考文章

这三篇都是比较基础且不错的文章

__EOF__

本文作者_TLSN
本文链接https://www.cnblogs.com/lordtianqiyi/articles/16151388.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   TLSN  阅读(441)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示