VT系列:VMCS表填写

[复制链接]

该用户从未签到

2380

主题

2433

帖子

9139

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9139
QQ
发表于 2018-7-15 15:46:48 | 显示全部楼层 |阅读模式

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

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

x

一共有5章表要填 分别是:

1.Guest State Area (客户机) 填写虚拟机相关的信息

2.Host State Area(宿主机) 填写真实机的相关信息

3.VM-Execution Control Fields(虚拟机运行控制域) 定义了我们的VT能拦截什么东西 指令 异常 操作。

4.VMEntry Control Fields(VMENTRY行为控制域) 写死的 只有x86 x64的区别

5.VMExit Control Fields(VMEXIT行为控制域) 写死的 只有x86 x64的区别


在填写之前需要注意一件事 就是当我们使用VMLanuch指令的时候 在VMLanuch下面的指令是执行不到的了


比如:

VMLanuch

Mov eax,1

Ret


如果VMLanuch(VVMCALL后VMOFF)成功那么Mov eax,1 和Ret是不会执行了,因为这个时候已经跑到虚拟机里面去执行了

那么我们需要得到Mov eax,1的地址当调用VMLanuch(VMCALL后VMOFF)之后让虚拟机的EIP指向mov eax,1的地址继续执行后面的代码


在填写VMCS中有一部分是麻烦的 NewBuilePill里面将这块封装成了模块

这里我们直接使用Newbluepill里面的代码

Common.cpp 和 common.h



步骤为:

1.判断处理器是否支持虚拟化

2.申请VMXON和VMCS的内存区域

3.设置版本号信息以及开启虚拟机汇编指令

4.保存客户机原始寄存器、填写VMCS表项

5.测试

6.关闭虚拟化的代码 调用VMCall 设置返回EIP 关闭虚拟化指令(CR4) 释放申请到的内存


这些需要一个结构保存申请到的VMXON VMCS的内存地址




  • typedef struct _VMX_CPU


  • {


  •          PVOIDpVMXONRegion; //VMXON的虚拟地址


  •          PHYSICAL_ADDRESSpVMXONRegion_PA; //VMXON的物理地址


  •          PVOIDpVMCSRegion; //VMCS的虚拟地址


  •          PHYSICAL_ADDRESSpVMCSRegion_PA; //VMCS的物理地址


  •          PVOIDpHostEsp; //主机的Esp





  •          BOOLEANbVTStartSuccess; //用于记录是否开启成功


  • }VMX_CPU,*PVMX_CPU;


增加两个函数

开启VT和关闭VT




  • NTSTATUS StartVirtualTechnology();


  • NTSTATUS StopVirtualTechnology();


实现如下:


  • #include "stdafx.h"


  • #include "vtsystem.h"


  • #include "vtasm.h"


  • #include "exithandler.h"


  • #include "common.h"





  • VMX_CPU g_VMXCPU;





  • NTSTATUS AllocateVMXRegion()


  • {


  •         PVOID pVMXONRegion;


  •         PVOID pVMCSRegion;


  •         PVOID pHostEsp;





  •         //必须4kb


  •         pVMXONRegion = ExAllocatePoolWithTag(NonPagedPool,0x1000,'vmon'); //4KB


  •         if (!pVMXONRegion)


  •         {


  •                 Log("ERROR:申请VMXON内存区域失败!",0);


  •                 return STATUS_MEMORY_NOT_ALLOCATED;


  •         }


  •         //最好zero


  •         RtlZeroMemory(pVMXONRegion,0x1000);





  •         //4kb就够了


  •         pVMCSRegion = ExAllocatePoolWithTag(NonPagedPool,0x1000,'vmcs');


  •         if (!pVMCSRegion)


  •         {


  •                 Log("ERROR:申请VMCS内存区域失败!",0);


  •                 ExFreePoolWithTag(pVMXONRegion,0x1000);


  •                 return STATUS_MEMORY_NOT_ALLOCATED;


  •         }


  •         //最好zero


  •         RtlZeroMemory(pVMCSRegion,0x1000);





  •         //用于给保存寄存器时当栈 0x2000后面会说


  •         pHostEsp = ExAllocatePoolWithTag(NonPagedPool,0x2000,'mini');


  •         if (!pHostEsp)


  •         {


  •                 Log("ERROR:申请宿主机堆载区域失败!",0);


  •                 ExFreePoolWithTag(pVMXONRegion,0x1000);


  •                 ExFreePoolWithTag(pVMCSRegion,0x1000);


  •                 return STATUS_MEMORY_NOT_ALLOCATED;


  •         }


  •         RtlZeroMemory(pHostEsp,0x2000);





  •         Log("TIP:VMXON内存区域地址",pVMXONRegion);


  •         Log("TIP:VMCS内存区域地址",pVMCSRegion);


  •         Log("TIP:宿主机堆载区域地址",pHostEsp);





  •         g_VMXCPU.pVMXONRegion = pVMXONRegion;


  •         g_VMXCPU.pVMXONRegion_PA = MmGetPhysicalAddress(pVMXONRegion);


  •         g_VMXCPU.pVMCSRegion = pVMCSRegion;


  •         g_VMXCPU.pVMCSRegion_PA = MmGetPhysicalAddress(pVMCSRegion);


  •         g_VMXCPU.pHostEsp = pHostEsp;


  •         return STATUS_SUCCESS;


  • }





  • //填写版本号信息和开启虚拟化汇编指令


  • void SetupVMXRegion()


  • {


  •         VMX_BASIC_MSR Msr;


  •         ULONG uRevId;


  •         _CR4 uCr4;


  •         _EFLAGS uEflags;





  •         RtlZeroMemory(&Msr,sizeof(Msr));





  •         *((PULONG)&Msr) = Asm_ReadMsr(MSR_IA32_VMX_BASIC);


  •         uRevId = Msr.RevId;





  •         //将Revid写入申请的到VMXON VMCS的前4个字节


  •         *((PULONG)g_VMXCPU.pVMXONRegion) = uRevId;


  •         *((PULONG)g_VMXCPU.pVMCSRegion) = uRevId;





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





  •         //开启虚拟化汇编指令


  •         *((PULONG)&uCr4) = Asm_GetCr4();


  •         uCr4.VMXE = 1;


  •         Asm_SetCr4(*((PULONG)&uCr4));





  •         //调用VmxOn指令启动虚拟化指令


  •         Vmx_VmxOn(g_VMXCPU.pVMXONRegion_PA.LowPart,g_VMXCPU.pVMXONRegion_PA.HighPart);





  •         //检测Vmxon指令是否成功 见intel手册3.15


  •         *((PULONG)&uEflags) = Asm_GetEflags();


  •         if (uEflags.CF != 0)


  •         {


  •                 Log("ERROR:VMXON指令调用失败!",0);


  •                 return;


  •         }


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


  • }





  • extern "C" void SetupVMCS()


  • {


  •         _EFLAGS uEflags;


  •         ULONG GdtBase,IdtBase;


  •         SEGMENT_SELECTOR SegmentSelector;


  •         ULONG uCPUBase,uExceptionBitmap;





  •         //需要Clear一下VMCS的物理地址


  •         Vmx_VmClear(g_VMXCPU.pVMCSRegion_PA.LowPart,g_VMXCPU.pVMCSRegion_PA.HighPart);


  •         //检测是否Clear成功


  •         *((PULONG)&uEflags) = Asm_GetEflags();


  •         if (uEflags.CF != 0 || uEflags.ZF != 0)


  •         {


  •                 Log("ERROR:VMCLEAR指令调用失败!",0);


  •                 return;


  •         }


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


  •         //设置VMCS的物理地址???


  •         Vmx_VmPtrld(g_VMXCPU.pVMCSRegion_PA.LowPart,g_VMXCPU.pVMCSRegion_PA.HighPart);





  •         //得到GDT IDT表Base 后面填表时需要用到


  •         GdtBase = Asm_GetGdtBase();


  •         IdtBase = Asm_GetIdtBase();





  •         //


  •         // 1.Guest State Area


  •         //





  •         /*


  •         需要填写以下信息


  •         GUEST_CR0                          AsmGetCr0


  •         GUEST_CR3                        AsmGetCr3


  •         GUEST_CR4                        AsmGetCr4





  •         GUEST_DR7                        0x400


  •         GUEST_RFLAGS                Asm_GetEflags





  •         GdtBase,ES FS DS CS SS GS TR LDTR 这里使用了NewBluePill里面的代码FillGuestSelectorData





  •         GUEST_GDTR_BASE                GdtBast


  •         GUEST_GDTR_LIMIT    Asm_GetGdtLimit


  •         GUEST_IDTR_BASE                IdtBase


  •         GUEST_IDTR_LIMIT          Asm_GetIdtLimit





  •         GUEST_IA32_DEBUGCTL        


  •         GUEST_IA32_DEBUGCTL_HIGH





  •         GUEST_SYSENTER_CS


  •         GUEST_SYSENTER_ESP


  •         GUEST_SYSENTER_EIP   //这个就是KiFastCallEntry ddvp里面就是修改了这个达到修改内核入口的目的





  •         GUEST_RSP                在保存寄存器时保存的GuestEsp  因为汇编里面的变量不能直接在CPP中使用 这里编写了一个汇编函数返回guest esp


  •         Asm_GetGuestESP Proc


  •                 mov eax,GuestESP


  •                 ret


  •         Asm_GetGuestESP Endp





  •         GUEST_RIP      在调用VmLanuch后要执行的EIP  这里必须让其返回到驱动加载时的EIP 否则BIOS或卡死


  •         Asm_GetGuestReturn Proc


  •                 mov eax,GuestReturn


  •                 ret


  •         Asm_GetGuestReturn Endp








  •         //必须要加上的 不知道干什么的 不加蓝屏或卡死


  •         GUEST_INTERRUPTIBILITY_INFO  0


  •         GUEST_ACTIVITY_STATE         0


  •         VMCS_LINK_POINTER                        0xffffffff


  •         VMCS_LINK_POINTER_HIGH                0xffffffff


  •         */


  •         Vmx_VmWrite(GUEST_CR0,Asm_GetCr0());


  •         Vmx_VmWrite(GUEST_CR3,Asm_GetCr3());


  •         Vmx_VmWrite(GUEST_CR4,Asm_GetCr4());





  •         Vmx_VmWrite(GUEST_DR7,0x400);


  •         Vmx_VmWrite(GUEST_RFLAGS,Asm_GetEflags());





  •         FillGuestSelectorData(GdtBase,ES,Asm_GetEs());


  •         FillGuestSelectorData(GdtBase,FS,Asm_GetFs());


  •         FillGuestSelectorData(GdtBase,DS,Asm_GetDs());


  •         FillGuestSelectorData(GdtBase,CS,Asm_GetCs());


  •         FillGuestSelectorData(GdtBase,SS,Asm_GetSs());


  •         FillGuestSelectorData(GdtBase,GS,Asm_GetGs());


  •         FillGuestSelectorData(GdtBase,TR,Asm_GetTr());


  •         FillGuestSelectorData(GdtBase,LDTR,Asm_GetLdtr());





  •         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,Asm_GetGuestESP());


  •         Vmx_VmWrite(GUEST_RIP,Asm_GetGuestReturn());// 指定vmlaunch客户机的入口点 这里我们让客户机继续执行加载驱动的代码





  •         Vmx_VmWrite(GUEST_INTERRUPTIBILITY_INFO, 0);


  •         Vmx_VmWrite(GUEST_ACTIVITY_STATE, 0);


  •         Vmx_VmWrite(VMCS_LINK_POINTER, 0xffffffff);


  •         Vmx_VmWrite(VMCS_LINK_POINTER_HIGH, 0xffffffff);





  •         //


  •         // 2.Host State Area


  •         //


  •         /*


  •         大部分同上


  •         需要关注2点


  •         一个是HOST_RSP  这个是给保存寄存器时用的栈 就是我们申请的hostEsp 这里它是反着用的 所以要加到尾部


  •         另一个是Host_RIP 这个就是定义我们的VMM处理程序的入口 当发生退出事件时 会调用这个地方


  •         */


  •         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);


  •         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);





  •         InitializeSegmentSelector(&SegmentSelector,Asm_GetFs(),GdtBase);


  •         Vmx_VmWrite(HOST_FS_BASE,SegmentSelector.base);


  •         InitializeSegmentSelector(&SegmentSelector,Asm_GetGs(),GdtBase);


  •         Vmx_VmWrite(HOST_GS_BASE,SegmentSelector.base);


  •         InitializeSegmentSelector(&SegmentSelector,Asm_GetTr(),GdtBase);


  •         Vmx_VmWrite(HOST_TR_BASE,SegmentSelector.base);





  •         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.pHostEsp) + 0x1FFF);//8KB 0x2000


  •         Vmx_VmWrite(HOST_RIP,(ULONG)&Asm_VMMEntryPoint);//这里定义我们的VMM处理程序入口





  •         //


  •         // 3.虚拟机运行控制域


  •         //





  •         /*


  •         最重要的地方


  •         这个控制域决定了这个VT能干什么


  •         前4个是和最后5个CR3必须的





  •         要添加拦截什么操作


  •         需要从MSR_IA32_VMX_PROCBASED_CTLS中得到一个数


  •         跟这个数做与运算即可


  •         完事后 使用VMwrite写到CPU_BASED_VM_EXEC_CONTROL即可


  •         */


  •         Vmx_VmWrite(PIN_BASED_VM_EXEC_CONTROL,VmxAdjustControls(0,MSR_IA32_VMX_PINBASED_CTLS));





  •         Vmx_VmWrite(PAGE_FAULT_ERROR_CODE_MASK,0);


  •         Vmx_VmWrite(PAGE_FAULT_ERROR_CODE_MATCH,0);


  •         Vmx_VmWrite(TSC_OFFSET,0);


  •         Vmx_VmWrite(TSC_OFFSET_HIGH,0);





  •         uCPUBase = VmxAdjustControls(0,MSR_IA32_VMX_PROCBASED_CTLS);





  •         //uCPUBase |= CPU_BASED_MOV_DR_EXITING; // 拦截调试寄存器操作


  •         //uCPUBase |= CPU_BASED_USE_IO_BITMAPS; // 拦截键盘鼠标消息


  •         //uCPUBase |= CPU_BASED_ACTIVATE_MSR_BITMAP; // 拦截MSR操作


  •         //................





  •         Vmx_VmWrite(CPU_BASED_VM_EXEC_CONTROL,uCPUBase);





  •         /*


  •         Vmx_VmWrite(IO_BITMAP_A,0);


  •         Vmx_VmWrite(IO_BITMAP_A_HIGH,0);


  •         Vmx_VmWrite(IO_BITMAP_B,0);


  •         Vmx_VmWrite(IO_BITMAP_B_HIGH,0);


  •         */





  •         Vmx_VmWrite(CR3_TARGET_COUNT,0);


  •         Vmx_VmWrite(CR3_TARGET_VALUE0,0);


  •         Vmx_VmWrite(CR3_TARGET_VALUE1,0);


  •         Vmx_VmWrite(CR3_TARGET_VALUE2,0);


  •         Vmx_VmWrite(CR3_TARGET_VALUE3,0);





  •         //


  •         // 4.VMEntry运行控制域


  •         //





  •         /*


  •         4-5 是固定不变的 只有x86和x64的区别


  •         */


  •         Vmx_VmWrite(VM_ENTRY_CONTROLS,VmxAdjustControls(0,MSR_IA32_VMX_ENTRY_CTLS));


  •         Vmx_VmWrite(VM_ENTRY_MSR_LOAD_COUNT,0);


  •         Vmx_VmWrite(VM_ENTRY_INTR_INFO_FIELD,0);








  •         //


  •         // 5.VMExit运行控制域


  •         //


  •         Vmx_VmWrite(VM_EXIT_CONTROLS,VmxAdjustControls(VM_EXIT_ACK_INTR_ON_EXIT,MSR_IA32_VMX_EXIT_CTLS));


  •         Vmx_VmWrite(VM_EXIT_MSR_LOAD_COUNT,0);


  •         Vmx_VmWrite(VM_EXIT_MSR_STORE_COUNT,0);








  •         //填写完后调用VmLaunch启动虚拟机


  •         Vmx_VmLaunch();





  •         //如果成功 这里永远不会被执行


  •         g_VMXCPU.bVTStartSuccess = FALSE;





  •         Log("ERROR:VmLaunch指令调用失败!",Vmx_VmRead(VM_INSTRUCTION_ERROR));


  • }





  • NTSTATUS StartVirtualTechnology()


  • {


  •         NTSTATUS status = STATUS_SUCCESS;


  •         //检测是否支持虚拟化


  •         if (!IsVTEnabled())


  •                 return STATUS_NOT_SUPPORTED;


  •         //申请VMXON VMCS内存区域


  •         status = AllocateVMXRegion();


  •         if (!NT_SUCCESS(status))


  •         {


  •                 Log("ERROR:VMX内存区域申请失败",0);


  •                 return STATUS_UNSUCCESSFUL;


  •         }


  •         Log("SUCCESS:VMX内存区域申请成功!",0);





  •         //填写版本号信息和开启虚拟化汇编指令VMXON


  •         SetupVMXRegion();


  •         g_VMXCPU.bVTStartSuccess = TRUE;





  •         //保存客户机寄存器、得到开启虚拟化后要执行的EIP(也就是前面说的Vmlanuch问题)、填写VMCS表


  •         //在保存好客户机寄存器 和返回地址后会调用SetupVMCS


  •         Asm_SetupVMCS();





  •         if (g_VMXCPU.bVTStartSuccess)


  •         {


  •                 Log("SUCCESS:开启VT成功!",0);


  •                 Log("SUCCESS:现在这个CPU进入了VMX模式.",0);


  •                 return STATUS_SUCCESS;


  •         }


  •         else Log("ERROR:开启VT失败!",0);


  •         return STATUS_UNSUCCESSFUL;


  • }





  • NTSTATUS StopVirtualTechnology()


  • {


  •         _CR4 uCr4;


  •         if(g_VMXCPU.bVTStartSuccess)


  •         {


  •                 //会进入我们的处理函数


  •                 Vmx_VmCall('SVT');





  •                 *((PULONG)&uCr4) = Asm_GetCr4();


  •                 uCr4.VMXE = 0;


  •                 Asm_SetCr4(*((PULONG)&uCr4));





  •                 ExFreePoolWithTag(g_VMXCPU.pVMXONRegion,'vmon');


  •                 ExFreePoolWithTag(g_VMXCPU.pVMCSRegion,'vmcs');


  •                 ExFreePoolWithTag(g_VMXCPU.pHostEsp,'mini');





  •                 Log("SUCCESS:关闭VT成功!",0);


  •                 Log("SUCCESS:现在这个CPU退出了VMX模式.",0);


  •         }





  •         return STATUS_SUCCESS;


  • }





  • 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. 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;


  •         }





  •         // 3. MSR


  •         *((PULONG)&msr) = Asm_ReadMsr(MSR_IA32_FEATURE_CONTROL);


  •         if (msr.Lock!=1)


  •         {


  •                 Log("ERROR:VT指令未被锁定!",0);


  •                 return FALSE;


  •         }


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


  •         return TRUE;


  • }


汇编代码实现:


  • .686p


  • .model flat, stdcall


  • option casemap:none





  • GetGuestRegsAddress Proto


  • VMMEntryPoint Proto


  • SetupVMCS Proto





  • .data


  • GuestESP dword ?


  • GuestReturn dword ?





  • EntryEAX dword ?


  • EntryECX dword ?


  • EntryEDX dword ?


  • EntryEBX dword ?


  • EntryESP dword ?


  • EntryEBP dword ?


  • EntryESI dword ?


  • EntryEDI dword ?


  • EntryEflags dword ?





  • .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_WriteMsr        Proc        Index:dword,LowPart,HighPart        


  •         mov        ecx, Index


  •         mov        eax, LowPart


  •         mov        edx, HighPart


  •         wrmsr


  •         ret


  • Asm_WriteMsr         Endp





  • Asm_ReadMsrEx                Proc        Index:dword,pMsr:dword


  •         pushad


  •         mov        ecx,Index


  •         rdmsr


  •         mov ebx,pMsr


  •         mov dword ptr [ebx],eax


  •         add ebx,4


  •         mov dword ptr [ebx],edx


  •         popad


  •         ret


  • Asm_ReadMsrEx                Endp





  • Asm_Invd Proc


  •         invd


  •         ret


  • Asm_Invd Endp





  • Asm_GetCs PROC


  •         mov                eax, cs


  •         ret


  • Asm_GetCs ENDP





  • Asm_GetDs PROC


  •         mov                eax, ds


  •         ret


  • Asm_GetDs ENDP





  • Asm_GetEs PROC


  •         mov                eax, es


  •         ret


  • Asm_GetEs ENDP





  • Asm_GetSs PROC


  •         mov                eax, ss


  •         ret


  • Asm_GetSs ENDP





  • Asm_GetFs PROC


  •         mov                eax, fs


  •         ret


  • Asm_GetFs ENDP





  • Asm_GetGs PROC


  •         mov                eax, gs


  •         ret


  • Asm_GetGs ENDP








  • Asm_GetCr0                Proc





  •         mov         eax, cr0


  •         ret





  • Asm_GetCr0                 Endp





  • Asm_GetCr3                Proc





  •         mov         eax, cr3


  •         ret


  • Asm_GetCr3                 Endp





  • Asm_GetCr4                Proc


  •         mov         eax, cr4


  •         ret


  • Asm_GetCr4                 Endp





  • Asm_SetCr0                Proc         NewCr0:dword





  •         mov         eax, NewCr0


  •         mov        cr0, eax


  •         ret


  • Asm_SetCr0                 Endp





  • Asm_SetCr2                Proc         NewCr2:dword





  •         mov         eax, NewCr2


  •         mov        cr2, eax


  •         ret


  • Asm_SetCr2                 Endp





  • Asm_SetCr3                Proc         NewCr3:dword





  •         mov         eax, NewCr3


  •         mov        cr3, eax


  •         ret


  • Asm_SetCr3                 Endp





  • Asm_SetCr4                Proc        NewCr4:dword





  •         mov         eax,NewCr4


  •         mov         cr4, eax


  •         ret





  • Asm_SetCr4                 Endp





  • Asm_GetDr0 PROC


  •         mov                eax, dr0


  •         ret


  • Asm_GetDr0 ENDP





  • Asm_GetDr1 PROC


  •         mov                eax, dr1


  •         ret


  • Asm_GetDr1 ENDP





  • Asm_GetDr2 PROC


  •         mov                eax, dr2


  •         ret


  • Asm_GetDr2 ENDP





  • Asm_GetDr3 PROC


  •         mov                eax, dr3


  •         ret


  • Asm_GetDr3 ENDP





  • Asm_GetDr6 PROC


  •         mov                eax, dr6


  •         ret


  • Asm_GetDr6 ENDP





  • Asm_GetDr7 PROC


  •         mov                eax, dr7


  •         ret


  • Asm_GetDr7 ENDP





  • Asm_SetDr0 PROC


  •         mov                dr0, ecx


  •         ret


  • Asm_SetDr0 ENDP





  • Asm_SetDr1 PROC


  •         mov                dr1, ecx


  •         ret


  • Asm_SetDr1 ENDP





  • Asm_SetDr2 PROC


  •         mov                dr2, ecx


  •         ret


  • Asm_SetDr2 ENDP





  • Asm_SetDr3 PROC


  •         mov                dr3, ecx


  •         ret


  • Asm_SetDr3 ENDP





  • Asm_SetDr6 PROC nNewDr6WORD


  •         mov eax,nNewDr6


  •         mov                dr6, eax


  •         ret


  • Asm_SetDr6 ENDP





  • Asm_SetDr7 PROC        nNewDr7WORD


  •         mov eax,nNewDr7


  •         mov                dr7, eax


  •         ret


  • Asm_SetDr7 ENDP





  • Asm_GetEflags PROC


  •         pushfd


  •         pop                eax


  •         ret


  • Asm_GetEflags ENDP





  • Asm_GetIdtBase PROC


  •         LOCAL        idtr[10]:BYTE





  •         sidt        idtr


  •         mov                eax, dword PTR idtr[2]


  •         ret


  • Asm_GetIdtBase ENDP





  • Asm_GetIdtLimit PROC


  •         LOCAL        idtr[10]:BYTE





  •         sidt        idtr


  •         mov                ax, WORD PTR idtr[0]


  •         ret


  • Asm_GetIdtLimit ENDP





  • Asm_GetGdtBase PROC


  •         LOCAL        gdtr[10]:BYTE





  •         sgdt        gdtr


  •         mov                eax, dword PTR gdtr[2]


  •         ret


  • Asm_GetGdtBase ENDP





  • Asm_GetGdtLimit PROC


  •         LOCAL        gdtr[10]:BYTE





  •         sgdt        gdtr


  •         mov                ax, WORD PTR gdtr[0]


  •         ret


  • Asm_GetGdtLimit ENDP





  • Asm_GetLdtr PROC


  •         sldt        eax


  •         ret


  • Asm_GetLdtr ENDP





  • Asm_GetTr PROC


  •         str        eax


  •         ret


  • Asm_GetTr ENDP





  • Asm_SetGdtr                Proc





  •         push        ecx


  •         shl        edx, 16


  •         push        edx





  •         lgdt        fword ptr [esp+2]


  •         pop        eax


  •         pop        eax


  •         ret


  • Asm_SetGdtr        Endp





  • Asm_SetIdtr                Proc





  •         push        ecx


  •         shl        edx, 16


  •         push        edx


  •         lidt        fword ptr [esp+2]


  •         pop        eax


  •         pop        eax


  •         ret


  • Asm_SetIdtr        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





  • Vmx_VmPtrld Proc LowPart:dword,HighPart:dword


  • ;!!!!!!!!!!!!!!!VMCS!!!!!!!!!!!!!!!!!!!


  •         push HighPart


  •         push LowPart


  •         vmptrld qword ptr [esp]


  •         add esp,8


  •         ret


  • Vmx_VmPtrld endp





  • Vmx_VmClear Proc LowPart:dword,HighPart:dword


  • ;!!!!!!!!!!!!!!!VMCS!!!!!!!!!!!!!!!!!!!


  •         push HighPart


  •         push LowPart


  •         vmclear qword ptr [esp]


  •         add esp,8


  •         ret


  • Vmx_VmClear endp





  • Vmx_VmRead Proc uses ecx Field:dword


  •         mov eax,Field


  •         vmread ecx,eax


  •         mov eax,ecx


  •         ret


  • Vmx_VmRead endp





  • Vmx_VmWrite Proc uses ecx Field:dword,Value:dword


  •         mov eax,Field


  •         mov ecx,Value


  •         vmwrite eax,ecx


  •         ret


  • Vmx_VmWrite endp





  • Vmx_VmCall Proc HyperCallNumberWORD


  •         pushad


  •         pushfd


  •         mov eax,HyperCallNumber


  •         vmcall





  •         popfd


  •         popad


  •         ret


  • Vmx_VmCall endp





  • Vmx_VmLaunch Proc


  •         vmlaunch


  •         ret


  • Vmx_VmLaunch endp





  • Vmx_VmResume Proc


  •         vmresume


  •         ret


  • Vmx_VmResume endp





  • Asm_GetVMXBasic Proc


  •         push 480h        ;        MSR_IA32_VMX_BASIC


  •         call Asm_ReadMsr


  •         ret


  • Asm_GetVMXBasic endp





  • Asm_GetCr0Ex Proc


  •         mov eax,cr0


  •         ret


  • Asm_GetCr0Ex endp





  • Asm_GetCr4Ex Proc


  •         mov eax,cr4


  •         ret


  • Asm_GetCr4Ex endp





  • Asm_SetCr0Ex Proc nNewCr0WORD


  •         mov eax,nNewCr0


  •         mov cr0,eax


  •         ret


  • Asm_SetCr0Ex endp





  • Asm_SetCr4Ex Proc nNewCr4WORD


  •         mov eax,nNewCr4


  •         mov cr4,eax


  •         ret


  • Asm_SetCr4Ex endp





  • Asm_GetEflagsEx Proc


  •         pushfd


  •         pop eax


  •         ret


  • Asm_GetEflagsEx endp





  • Asm_GetGuestESP Proc


  •         mov eax,GuestESP


  •         ret


  • Asm_GetGuestESP Endp





  • Asm_GetGuestReturn Proc


  •         mov eax,GuestReturn


  •         ret


  • Asm_GetGuestReturn Endp





  • Asm_AfterVMXOff Proc JmpESP:dword,JmpEIP:dword


  •         mov esp,JmpESP


  •         jmp JmpEIP


  •         ret


  • Asm_AfterVMXOff Endp





  • Asm_RunToVMCS Proc


  •         mov eax,[esp]


  •         mov GuestReturn,eax ;获取返回地址,让vmlaunch后客户机继续执行驱动加载的代码





  •         call SetupVMCS


  •         ret


  • Asm_RunToVMCS Endp





  • Asm_SetupVMCS Proc


  •         cli


  •         mov GuestESP,esp





  •         mov EntryEAX,eax


  •         mov EntryECX,ecx


  •         mov EntryEDX,edx


  •         mov EntryEBX,ebx


  •         mov EntryESP,esp


  •         mov EntryEBP,ebp


  •         mov EntryEDI,edi


  •         mov EntryESI,esi


  •         pushfd


  •         pop EntryEflags





  •         call Asm_RunToVMCS





  •         push EntryEflags


  •         popfd


  •         mov eax,EntryEAX


  •         mov ecx,EntryECX


  •         mov edx,EntryEDX


  •         mov ebx,EntryEBX


  •         mov esp,EntryESP


  •         mov ebp,EntryEBP


  •         mov esi,EntryESI


  •         mov edi,EntryEDI





  •         mov esp,GuestESP


  •         sti


  •         ret


  • Asm_SetupVMCS Endp





  • Asm_VMMEntryPoint Proc


  •         cli


  •         push eax


  •         push ecx


  •         push edx


  •         push ebx


  •         push esp     ;HOST_RSP


  •         push ebp


  •         push edi


  •         push esi





  •         mov [esp-1280h],eax


  •         mov [esp-1284h],ebx


  •         call GetGuestRegsAddress


  •         mov [eax+4h],ecx


  •         mov [eax+8h],edx


  •         mov [eax+0Ch],ebx


  •         mov [eax+10h],esp


  •         mov [eax+14h],ebp


  •         mov [eax+18h],esi


  •         mov [eax+1Ch],edi


  •         mov ebx,[esp-1280h]


  •         mov [eax],ebx


  •         mov eax,[esp-1280h]


  •         mov ebx,[esp-1284h]





  •         call VMMEntryPoint





  •         pop esi


  •         pop edi


  •         pop ebp


  •         pop esp


  •         pop ebx


  •         pop edx


  •         pop ecx


  •         pop eax





  •         call GetGuestRegsAddress


  •         mov ecx,[eax+4h]


  •         mov edx,[eax+8h]


  •         mov ebx,[eax+0Ch]


  •         mov esp,[eax+10h]


  •         mov ebp,[eax+14h]


  •         mov esi,[eax+18h]


  •         mov edi,[eax+1Ch]


  •         mov eax,[eax]


  •         sti


  •         vmresume


  • Asm_VMMEntryPoint Endp








  • END


还记得前面VMCALL 这里我们要处理下

当需要关闭VT时 我们在虚拟机调用VMCALL 这时进入VMM

我们需要调用VMOFF关闭VT 但关闭VT后EIP是在关闭VT的这里 我们要让它会到调用VMCALL的下一条指令去




  • void HandleVmCall()


  • {


  •         ULONG JmpEIP;


  •         if (g_GuestRegs.eax == 'SVT')


  •         {


  •                 //得到调用VmCall指令的下一句指令地址


  •                 JmpEIP = g_GuestRegs.eip + Vmx_VmRead(VM_EXIT_INSTRUCTION_LEN);


  •                 //调用VmxOff


  •                 Vmx_VmxOff();





  •                 //设置返回esp和eip


  •                 Asm_AfterVMXOff(g_GuestRegs.esp,JmpEIP);


  •                 /*


  •                 Asm_AfterVMXOff Proc JmpESP:dword,JmpEIP:dword


  •                         mov esp,JmpESP


  •                         jmp JmpEIP


  •                         ret


  •                 Asm_AfterVMXOff Endp


  •                 */


  •         }


  • }


代码注释的很清楚不在多解释

目前代码只能运行在单核的x86 intel cpu 的系统中

后面会补充在多核x64


回复

使用道具 举报

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

本版积分规则

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