看流星社区

 找回密码
 注册账号
查看: 2057|回复: 0

VT系列:VMCS表填写

[复制链接]

该用户从未签到

发表于 2017-6-1 12:17:34 | 显示全部楼层 |阅读模式


一共有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的内存地址
  1. typedef struct _VMX_CPU
  2. {
  3.          PVOIDpVMXONRegion; //VMXON的虚拟地址
  4.          PHYSICAL_ADDRESSpVMXONRegion_PA; //VMXON的物理地址
  5.          PVOIDpVMCSRegion; //VMCS的虚拟地址
  6.          PHYSICAL_ADDRESSpVMCSRegion_PA; //VMCS的物理地址
  7.          PVOIDpHostEsp; //主机的Esp
  8.          BOOLEANbVTStartSuccess; //用于记录是否开启成功
  9. }VMX_CPU,*PVMX_CPU;
复制代码

增加两个函数
开启VT和关闭VT
  1. NTSTATUS StartVirtualTechnology();
  2. NTSTATUS StopVirtualTechnology();
复制代码
实现如下:
  1. #include "stdafx.h"
  2. #include "vtsystem.h"
  3. #include "vtasm.h"
  4. #include "exithandler.h"
  5. #include "common.h"
  6. VMX_CPU g_VMXCPU;
  7. NTSTATUS AllocateVMXRegion()
  8. {
  9.         PVOID pVMXONRegion;
  10.         PVOID pVMCSRegion;
  11.         PVOID pHostEsp;
  12.         //必须4kb
  13.         pVMXONRegion = ExAllocatePoolWithTag(NonPagedPool,0x1000,'vmon'); //4KB
  14.         if (!pVMXONRegion)
  15.         {
  16.                 Log("ERROR:申请VMXON内存区域失败!",0);
  17.                 return STATUS_MEMORY_NOT_ALLOCATED;
  18.         }
  19.         //最好zero
  20.         RtlZeroMemory(pVMXONRegion,0x1000);
  21.         //4kb就够了
  22.         pVMCSRegion = ExAllocatePoolWithTag(NonPagedPool,0x1000,'vmcs');
  23.         if (!pVMCSRegion)
  24.         {
  25.                 Log("ERROR:申请VMCS内存区域失败!",0);
  26.                 ExFreePoolWithTag(pVMXONRegion,0x1000);
  27.                 return STATUS_MEMORY_NOT_ALLOCATED;
  28.         }
  29.         //最好zero
  30.         RtlZeroMemory(pVMCSRegion,0x1000);
  31.         //用于给保存寄存器时当栈 0x2000后面会说
  32.         pHostEsp = ExAllocatePoolWithTag(NonPagedPool,0x2000,'mini');
  33.         if (!pHostEsp)
  34.         {
  35.                 Log("ERROR:申请宿主机堆载区域失败!",0);
  36.                 ExFreePoolWithTag(pVMXONRegion,0x1000);
  37.                 ExFreePoolWithTag(pVMCSRegion,0x1000);
  38.                 return STATUS_MEMORY_NOT_ALLOCATED;
  39.         }
  40.         RtlZeroMemory(pHostEsp,0x2000);
  41.         Log("TIP:VMXON内存区域地址",pVMXONRegion);
  42.         Log("TIP:VMCS内存区域地址",pVMCSRegion);
  43.         Log("TIP:宿主机堆载区域地址",pHostEsp);
  44.         g_VMXCPU.pVMXONRegion = pVMXONRegion;
  45.         g_VMXCPU.pVMXONRegion_PA = MmGetPhysicalAddress(pVMXONRegion);
  46.         g_VMXCPU.pVMCSRegion = pVMCSRegion;
  47.         g_VMXCPU.pVMCSRegion_PA = MmGetPhysicalAddress(pVMCSRegion);
  48.         g_VMXCPU.pHostEsp = pHostEsp;
  49.         return STATUS_SUCCESS;
  50. }
  51. //填写版本号信息和开启虚拟化汇编指令
  52. void SetupVMXRegion()
  53. {
  54.         VMX_BASIC_MSR Msr;
  55.         ULONG uRevId;
  56.         _CR4 uCr4;
  57.         _EFLAGS uEflags;
  58.         RtlZeroMemory(&Msr,sizeof(Msr));
  59.         *((PULONG)&Msr) = Asm_ReadMsr(MSR_IA32_VMX_BASIC);
  60.         uRevId = Msr.RevId;
  61.         //将Revid写入申请的到VMXON VMCS的前4个字节
  62.         *((PULONG)g_VMXCPU.pVMXONRegion) = uRevId;
  63.         *((PULONG)g_VMXCPU.pVMCSRegion) = uRevId;
  64.         Log("TIP:VMX版本号信息",uRevId);
  65.         //开启虚拟化汇编指令
  66.         *((PULONG)&uCr4) = Asm_GetCr4();
  67.         uCr4.VMXE = 1;
  68.         Asm_SetCr4(*((PULONG)&uCr4));
  69.         //调用VmxOn指令启动虚拟化指令
  70.         Vmx_VmxOn(g_VMXCPU.pVMXONRegion_PA.LowPart,g_VMXCPU.pVMXONRegion_PA.HighPart);
  71.         //检测Vmxon指令是否成功 见intel手册3.15
  72.         *((PULONG)&uEflags) = Asm_GetEflags();
  73.         if (uEflags.CF != 0)
  74.         {
  75.                 Log("ERROR:VMXON指令调用失败!",0);
  76.                 return;
  77.         }
  78.         Log("SUCCESS:VMXON指令调用成功!",0);
  79. }
  80. extern "C" void SetupVMCS()
  81. {
  82.         _EFLAGS uEflags;
  83.         ULONG GdtBase,IdtBase;
  84.         SEGMENT_SELECTOR SegmentSelector;
  85.         ULONG uCPUBase,uExceptionBitmap;
  86.         //需要Clear一下VMCS的物理地址
  87.         Vmx_VmClear(g_VMXCPU.pVMCSRegion_PA.LowPart,g_VMXCPU.pVMCSRegion_PA.HighPart);
  88.         //检测是否Clear成功
  89.         *((PULONG)&uEflags) = Asm_GetEflags();
  90.         if (uEflags.CF != 0 || uEflags.ZF != 0)
  91.         {
  92.                 Log("ERROR:VMCLEAR指令调用失败!",0);
  93.                 return;
  94.         }
  95.         Log("SUCCESS:VMCLEAR指令调用成功!",0);
  96.         //设置VMCS的物理地址???
  97.         Vmx_VmPtrld(g_VMXCPU.pVMCSRegion_PA.LowPart,g_VMXCPU.pVMCSRegion_PA.HighPart);
  98.         //得到GDT IDT表Base 后面填表时需要用到
  99.         GdtBase = Asm_GetGdtBase();
  100.         IdtBase = Asm_GetIdtBase();
  101.         //
  102.         // 1.Guest State Area
  103.         //
  104.         /*
  105.         需要填写以下信息
  106.         GUEST_CR0                          AsmGetCr0
  107.         GUEST_CR3                        AsmGetCr3
  108.         GUEST_CR4                        AsmGetCr4
  109.         GUEST_DR7                        0x400
  110.         GUEST_RFLAGS                Asm_GetEflags
  111.         GdtBase,ES FS DS CS SS GS TR LDTR 这里使用了NewBluePill里面的代码FillGuestSelectorData
  112.         GUEST_GDTR_BASE                GdtBast
  113.         GUEST_GDTR_LIMIT    Asm_GetGdtLimit
  114.         GUEST_IDTR_BASE                IdtBase
  115.         GUEST_IDTR_LIMIT          Asm_GetIdtLimit
  116.         GUEST_IA32_DEBUGCTL       
  117.         GUEST_IA32_DEBUGCTL_HIGH
  118.        
  119.         GUEST_SYSENTER_CS
  120.         GUEST_SYSENTER_ESP
  121.         GUEST_SYSENTER_EIP   //这个就是KiFastCallEntry ddvp里面就是修改了这个达到修改内核入口的目的
  122.         GUEST_RSP                在保存寄存器时保存的GuestEsp  因为汇编里面的变量不能直接在CPP中使用 这里编写了一个汇编函数返回guest esp
  123.         Asm_GetGuestESP Proc
  124.                 mov eax,GuestESP
  125.                 ret
  126.         Asm_GetGuestESP Endp
  127.         GUEST_RIP      在调用VmLanuch后要执行的EIP  这里必须让其返回到驱动加载时的EIP 否则BIOS或卡死
  128.         Asm_GetGuestReturn Proc
  129.                 mov eax,GuestReturn
  130.                 ret
  131.         Asm_GetGuestReturn Endp
  132.         //必须要加上的 不知道干什么的 不加蓝屏或卡死
  133.         GUEST_INTERRUPTIBILITY_INFO  0
  134.         GUEST_ACTIVITY_STATE         0
  135.         VMCS_LINK_POINTER                        0xffffffff
  136.         VMCS_LINK_POINTER_HIGH                0xffffffff
  137.         */
  138.         Vmx_VmWrite(GUEST_CR0,Asm_GetCr0());
  139.         Vmx_VmWrite(GUEST_CR3,Asm_GetCr3());
  140.         Vmx_VmWrite(GUEST_CR4,Asm_GetCr4());
  141.         Vmx_VmWrite(GUEST_DR7,0x400);
  142.         Vmx_VmWrite(GUEST_RFLAGS,Asm_GetEflags());
  143.         FillGuestSelectorData(GdtBase,ES,Asm_GetEs());
  144.         FillGuestSelectorData(GdtBase,FS,Asm_GetFs());
  145.         FillGuestSelectorData(GdtBase,DS,Asm_GetDs());
  146.         FillGuestSelectorData(GdtBase,CS,Asm_GetCs());
  147.         FillGuestSelectorData(GdtBase,SS,Asm_GetSs());
  148.         FillGuestSelectorData(GdtBase,GS,Asm_GetGs());
  149.         FillGuestSelectorData(GdtBase,TR,Asm_GetTr());
  150.         FillGuestSelectorData(GdtBase,LDTR,Asm_GetLdtr());
  151.         Vmx_VmWrite(GUEST_GDTR_BASE,GdtBase);
  152.         Vmx_VmWrite(GUEST_GDTR_LIMIT,Asm_GetGdtLimit());
  153.         Vmx_VmWrite(GUEST_IDTR_BASE,IdtBase);
  154.         Vmx_VmWrite(GUEST_IDTR_LIMIT,Asm_GetIdtLimit());
  155.         Vmx_VmWrite(GUEST_IA32_DEBUGCTL,Asm_ReadMsr(MSR_IA32_DEBUGCTL)&0xFFFFFFFF);
  156.         Vmx_VmWrite(GUEST_IA32_DEBUGCTL_HIGH,Asm_ReadMsr(MSR_IA32_DEBUGCTL)>>32);
  157.         Vmx_VmWrite(GUEST_SYSENTER_CS,Asm_ReadMsr(MSR_IA32_SYSENTER_CS)&0xFFFFFFFF);
  158.         Vmx_VmWrite(GUEST_SYSENTER_ESP,Asm_ReadMsr(MSR_IA32_SYSENTER_ESP)&0xFFFFFFFF);
  159.         Vmx_VmWrite(GUEST_SYSENTER_EIP,Asm_ReadMsr(MSR_IA32_SYSENTER_EIP)&0xFFFFFFFF); // KiFastCallEntry
  160.         Vmx_VmWrite(GUEST_RSP,Asm_GetGuestESP());
  161.         Vmx_VmWrite(GUEST_RIP,Asm_GetGuestReturn());// 指定vmlaunch客户机的入口点 这里我们让客户机继续执行加载驱动的代码
  162.         Vmx_VmWrite(GUEST_INTERRUPTIBILITY_INFO, 0);
  163.         Vmx_VmWrite(GUEST_ACTIVITY_STATE, 0);
  164.         Vmx_VmWrite(VMCS_LINK_POINTER, 0xffffffff);
  165.         Vmx_VmWrite(VMCS_LINK_POINTER_HIGH, 0xffffffff);
  166.         //
  167.         // 2.Host State Area
  168.         //
  169.         /*
  170.         大部分同上
  171.         需要关注2点
  172.         一个是HOST_RSP  这个是给保存寄存器时用的栈 就是我们申请的hostEsp 这里它是反着用的 所以要加到尾部
  173.         另一个是Host_RIP 这个就是定义我们的VMM处理程序的入口 当发生退出事件时 会调用这个地方
  174.         */
  175.         Vmx_VmWrite(HOST_CR0,Asm_GetCr0());
  176.         Vmx_VmWrite(HOST_CR3,Asm_GetCr3());
  177.         Vmx_VmWrite(HOST_CR4,Asm_GetCr4());
  178.         Vmx_VmWrite(HOST_ES_SELECTOR,Asm_GetEs() & 0xFFF8);
  179.         Vmx_VmWrite(HOST_CS_SELECTOR,Asm_GetCs() & 0xFFF8);
  180.         Vmx_VmWrite(HOST_DS_SELECTOR,Asm_GetDs() & 0xFFF8);
  181.         Vmx_VmWrite(HOST_FS_SELECTOR,Asm_GetFs() & 0xFFF8);
  182.         Vmx_VmWrite(HOST_GS_SELECTOR,Asm_GetGs() & 0xFFF8);
  183.         Vmx_VmWrite(HOST_SS_SELECTOR,Asm_GetSs() & 0xFFF8);
  184.         Vmx_VmWrite(HOST_TR_SELECTOR,Asm_GetTr() & 0xFFF8);
  185.         InitializeSegmentSelector(&SegmentSelector,Asm_GetFs(),GdtBase);
  186.         Vmx_VmWrite(HOST_FS_BASE,SegmentSelector.base);
  187.         InitializeSegmentSelector(&SegmentSelector,Asm_GetGs(),GdtBase);
  188.         Vmx_VmWrite(HOST_GS_BASE,SegmentSelector.base);
  189.         InitializeSegmentSelector(&SegmentSelector,Asm_GetTr(),GdtBase);
  190.         Vmx_VmWrite(HOST_TR_BASE,SegmentSelector.base);
  191.         Vmx_VmWrite(HOST_GDTR_BASE,GdtBase);
  192.         Vmx_VmWrite(HOST_IDTR_BASE,IdtBase);
  193.         Vmx_VmWrite(HOST_IA32_SYSENTER_CS,Asm_ReadMsr(MSR_IA32_SYSENTER_CS)&0xFFFFFFFF);
  194.         Vmx_VmWrite(HOST_IA32_SYSENTER_ESP,Asm_ReadMsr(MSR_IA32_SYSENTER_ESP)&0xFFFFFFFF);
  195.         Vmx_VmWrite(HOST_IA32_SYSENTER_EIP,Asm_ReadMsr(MSR_IA32_SYSENTER_EIP)&0xFFFFFFFF); // KiFastCallEntry
  196.         Vmx_VmWrite(HOST_RSP,((ULONG)g_VMXCPU.pHostEsp) + 0x1FFF);//8KB 0x2000
  197.         Vmx_VmWrite(HOST_RIP,(ULONG)&Asm_VMMEntryPoint);//这里定义我们的VMM处理程序入口
  198.         //
  199.         // 3.虚拟机运行控制域
  200.         //
  201.         /*
  202.         最重要的地方
  203.         这个控制域决定了这个VT能干什么
  204.         前4个是和最后5个CR3必须的
  205.         要添加拦截什么操作
  206.         需要从MSR_IA32_VMX_PROCBASED_CTLS中得到一个数
  207.         跟这个数做与运算即可
  208.         完事后 使用VMwrite写到CPU_BASED_VM_EXEC_CONTROL即可
  209.         */
  210.         Vmx_VmWrite(PIN_BASED_VM_EXEC_CONTROL,VmxAdjustControls(0,MSR_IA32_VMX_PINBASED_CTLS));
  211.         Vmx_VmWrite(PAGE_FAULT_ERROR_CODE_MASK,0);
  212.         Vmx_VmWrite(PAGE_FAULT_ERROR_CODE_MATCH,0);
  213.         Vmx_VmWrite(TSC_OFFSET,0);
  214.         Vmx_VmWrite(TSC_OFFSET_HIGH,0);
  215.         uCPUBase = VmxAdjustControls(0,MSR_IA32_VMX_PROCBASED_CTLS);
  216.         //uCPUBase |= CPU_BASED_MOV_DR_EXITING; // 拦截调试寄存器操作
  217.         //uCPUBase |= CPU_BASED_USE_IO_BITMAPS; // 拦截键盘鼠标消息
  218.         //uCPUBase |= CPU_BASED_ACTIVATE_MSR_BITMAP; // 拦截MSR操作
  219.         //................
  220.        
  221.         Vmx_VmWrite(CPU_BASED_VM_EXEC_CONTROL,uCPUBase);
  222.         /*
  223.         Vmx_VmWrite(IO_BITMAP_A,0);
  224.         Vmx_VmWrite(IO_BITMAP_A_HIGH,0);
  225.         Vmx_VmWrite(IO_BITMAP_B,0);
  226.         Vmx_VmWrite(IO_BITMAP_B_HIGH,0);
  227.         */
  228.         Vmx_VmWrite(CR3_TARGET_COUNT,0);
  229.         Vmx_VmWrite(CR3_TARGET_VALUE0,0);
  230.         Vmx_VmWrite(CR3_TARGET_VALUE1,0);
  231.         Vmx_VmWrite(CR3_TARGET_VALUE2,0);
  232.         Vmx_VmWrite(CR3_TARGET_VALUE3,0);
  233.         //
  234.         // 4.VMEntry运行控制域
  235.         //
  236.         /*
  237.         4-5 是固定不变的 只有x86和x64的区别
  238.         */
  239.         Vmx_VmWrite(VM_ENTRY_CONTROLS,VmxAdjustControls(0,MSR_IA32_VMX_ENTRY_CTLS));
  240.         Vmx_VmWrite(VM_ENTRY_MSR_LOAD_COUNT,0);
  241.         Vmx_VmWrite(VM_ENTRY_INTR_INFO_FIELD,0);
  242.         //
  243.         // 5.VMExit运行控制域
  244.         //
  245.         Vmx_VmWrite(VM_EXIT_CONTROLS,VmxAdjustControls(VM_EXIT_ACK_INTR_ON_EXIT,MSR_IA32_VMX_EXIT_CTLS));
  246.         Vmx_VmWrite(VM_EXIT_MSR_LOAD_COUNT,0);
  247.         Vmx_VmWrite(VM_EXIT_MSR_STORE_COUNT,0);
  248.         //填写完后调用VmLaunch启动虚拟机
  249.         Vmx_VmLaunch();
  250.         //如果成功 这里永远不会被执行
  251.         g_VMXCPU.bVTStartSuccess = FALSE;
  252.         Log("ERROR:VmLaunch指令调用失败!",Vmx_VmRead(VM_INSTRUCTION_ERROR));
  253. }
  254. NTSTATUS StartVirtualTechnology()
  255. {
  256.         NTSTATUS status = STATUS_SUCCESS;
  257.         //检测是否支持虚拟化
  258.         if (!IsVTEnabled())
  259.                 return STATUS_NOT_SUPPORTED;
  260.         //申请VMXON VMCS内存区域
  261.         status = AllocateVMXRegion();
  262.         if (!NT_SUCCESS(status))
  263.         {
  264.                 Log("ERROR:VMX内存区域申请失败",0);
  265.                 return STATUS_UNSUCCESSFUL;
  266.         }
  267.         Log("SUCCESS:VMX内存区域申请成功!",0);
  268.         //填写版本号信息和开启虚拟化汇编指令VMXON
  269.         SetupVMXRegion();
  270.         g_VMXCPU.bVTStartSuccess = TRUE;
  271.         //保存客户机寄存器、得到开启虚拟化后要执行的EIP(也就是前面说的Vmlanuch问题)、填写VMCS表
  272.         //在保存好客户机寄存器 和返回地址后会调用SetupVMCS
  273.         Asm_SetupVMCS();
  274.         if (g_VMXCPU.bVTStartSuccess)
  275.         {
  276.                 Log("SUCCESS:开启VT成功!",0);
  277.                 Log("SUCCESS:现在这个CPU进入了VMX模式.",0);
  278.                 return STATUS_SUCCESS;
  279.         }
  280.         else Log("ERROR:开启VT失败!",0);
  281.         return STATUS_UNSUCCESSFUL;
  282. }
  283. NTSTATUS StopVirtualTechnology()
  284. {
  285.         _CR4 uCr4;
  286.         if(g_VMXCPU.bVTStartSuccess)
  287.         {
  288.                 //会进入我们的处理函数
  289.                 Vmx_VmCall('SVT');
  290.                
  291.                 *((PULONG)&uCr4) = Asm_GetCr4();
  292.                 uCr4.VMXE = 0;
  293.                 Asm_SetCr4(*((PULONG)&uCr4));
  294.                 ExFreePoolWithTag(g_VMXCPU.pVMXONRegion,'vmon');
  295.                 ExFreePoolWithTag(g_VMXCPU.pVMCSRegion,'vmcs');
  296.                 ExFreePoolWithTag(g_VMXCPU.pHostEsp,'mini');
  297.                 Log("SUCCESS:关闭VT成功!",0);
  298.                 Log("SUCCESS:现在这个CPU退出了VMX模式.",0);
  299.         }
  300.         return STATUS_SUCCESS;
  301. }
  302. BOOLEAN IsVTEnabled()
  303. {
  304.         ULONG uRet_EAX,uRet_ECX,uRet_EDX,uRet_EBX;
  305.         _CPUID_ECX uCPUID;
  306.         _CR0 uCr0;
  307.         _CR4 uCr4;
  308.         IA32_FEATURE_CONTROL_MSR msr;
  309.         //1. CPUID
  310.         Asm_CPUID(1,&uRet_EAX,&uRet_EBX,&uRet_ECX,&uRet_EDX);
  311.         *((PULONG)&uCPUID) = uRet_ECX;
  312.         if (uCPUID.VMX != 1)
  313.         {
  314.                 Log("ERROR:这个CPU不支持VT!",0);
  315.                 return FALSE;
  316.         }
  317.         // 2. CR0 CR4
  318.         *((PULONG)&uCr0) = Asm_GetCr0();
  319.         *((PULONG)&uCr4) = Asm_GetCr4();
  320.         if (uCr0.PE != 1||uCr0.PG!=1||uCr0.NE!=1)
  321.         {
  322.                 Log("ERROR:这个CPU没有开启VT!",0);
  323.                 return FALSE;
  324.         }
  325.         if (uCr4.VMXE == 1)
  326.         {
  327.                 Log("ERROR:这个CPU已经开启了VT!",0);
  328.                 Log("可能是别的驱动已经占用了VT,你必须关闭它后才能开启。",0);
  329.                 return FALSE;
  330.         }
  331.         // 3. MSR
  332.         *((PULONG)&msr) = Asm_ReadMsr(MSR_IA32_FEATURE_CONTROL);
  333.         if (msr.Lock!=1)
  334.         {
  335.                 Log("ERROR:VT指令未被锁定!",0);
  336.                 return FALSE;
  337.         }
  338.         Log("SUCCESS:这个CPU支持VT!",0);
  339.         return TRUE;
  340. }
复制代码
汇编代码实现:
  1. .686p
  2. .model flat, stdcall
  3. option casemap:none
  4. GetGuestRegsAddress Proto
  5. VMMEntryPoint Proto
  6. SetupVMCS Proto
  7. .data
  8. GuestESP dword ?
  9. GuestReturn dword ?
  10. EntryEAX dword ?
  11. EntryECX dword ?
  12. EntryEDX dword ?
  13. EntryEBX dword ?
  14. EntryESP dword ?
  15. EntryEBP dword ?
  16. EntryESI dword ?
  17. EntryEDI dword ?
  18. EntryEflags dword ?
  19. .code
  20. Asm_CPUID        Proc        uses ebx esi edi fn:dword, ret_eax:dword,ret_ebx:dword,ret_ecx:dword, ret_edx:dword
  21.         mov        eax, fn
  22.         cpuid
  23.         mov        esi, ret_eax
  24.         mov        dword ptr [esi], eax
  25.         mov        esi, ret_ebx
  26.         mov        dword ptr [esi], ebx
  27.         mov        esi, ret_ecx
  28.         mov        dword ptr [esi], ecx
  29.         mov        esi, ret_edx
  30.         mov        dword ptr [esi], edx
  31.         ret
  32. Asm_CPUID         Endp
  33. Asm_ReadMsr                Proc        Index:dword
  34.         mov        ecx,Index
  35.         rdmsr
  36.         ret
  37. Asm_ReadMsr                Endp
  38. Asm_WriteMsr        Proc        Index:dword,LowPart,HighPart       
  39.         mov        ecx, Index
  40.         mov        eax, LowPart
  41.         mov        edx, HighPart
  42.         wrmsr
  43.         ret
  44. Asm_WriteMsr         Endp
  45. Asm_ReadMsrEx                Proc        Index:dword,pMsr:dword
  46.         pushad
  47.         mov        ecx,Index
  48.         rdmsr
  49.         mov ebx,pMsr
  50.         mov dword ptr [ebx],eax
  51.         add ebx,4
  52.         mov dword ptr [ebx],edx
  53.         popad
  54.         ret
  55. Asm_ReadMsrEx                Endp
  56. Asm_Invd Proc
  57.         invd
  58.         ret
  59. Asm_Invd Endp
  60. Asm_GetCs PROC
  61.         mov                eax, cs
  62.         ret
  63. Asm_GetCs ENDP
  64. Asm_GetDs PROC
  65.         mov                eax, ds
  66.         ret
  67. Asm_GetDs ENDP
  68. Asm_GetEs PROC
  69.         mov                eax, es
  70.         ret
  71. Asm_GetEs ENDP
  72. Asm_GetSs PROC
  73.         mov                eax, ss
  74.         ret
  75. Asm_GetSs ENDP
  76. Asm_GetFs PROC
  77.         mov                eax, fs
  78.         ret
  79. Asm_GetFs ENDP
  80. Asm_GetGs PROC
  81.         mov                eax, gs
  82.         ret
  83. Asm_GetGs ENDP
  84. Asm_GetCr0                Proc
  85.        
  86.         mov         eax, cr0
  87.         ret
  88.        
  89. Asm_GetCr0                 Endp
  90. Asm_GetCr3                Proc
  91.        
  92.         mov         eax, cr3
  93.         ret
  94. Asm_GetCr3                 Endp
  95. Asm_GetCr4                Proc
  96.         mov         eax, cr4
  97.         ret
  98. Asm_GetCr4                 Endp
  99. Asm_SetCr0                Proc         NewCr0:dword
  100.        
  101.         mov         eax, NewCr0
  102.         mov        cr0, eax
  103.         ret
  104. Asm_SetCr0                 Endp
  105. Asm_SetCr2                Proc         NewCr2:dword
  106.        
  107.         mov         eax, NewCr2
  108.         mov        cr2, eax
  109.         ret
  110. Asm_SetCr2                 Endp
  111. Asm_SetCr3                Proc         NewCr3:dword
  112.        
  113.         mov         eax, NewCr3
  114.         mov        cr3, eax
  115.         ret
  116. Asm_SetCr3                 Endp
  117. Asm_SetCr4                Proc        NewCr4:dword
  118.        
  119.         mov         eax,NewCr4
  120.         mov         cr4, eax
  121.         ret
  122.        
  123. Asm_SetCr4                 Endp
  124. Asm_GetDr0 PROC
  125.         mov                eax, dr0
  126.         ret
  127. Asm_GetDr0 ENDP
  128. Asm_GetDr1 PROC
  129.         mov                eax, dr1
  130.         ret
  131. Asm_GetDr1 ENDP
  132. Asm_GetDr2 PROC
  133.         mov                eax, dr2
  134.         ret
  135. Asm_GetDr2 ENDP
  136. Asm_GetDr3 PROC
  137.         mov                eax, dr3
  138.         ret
  139. Asm_GetDr3 ENDP
  140. Asm_GetDr6 PROC
  141.         mov                eax, dr6
  142.         ret
  143. Asm_GetDr6 ENDP
  144. Asm_GetDr7 PROC
  145.         mov                eax, dr7
  146.         ret
  147. Asm_GetDr7 ENDP
  148. Asm_SetDr0 PROC
  149.         mov                dr0, ecx
  150.         ret
  151. Asm_SetDr0 ENDP
  152. Asm_SetDr1 PROC
  153.         mov                dr1, ecx
  154.         ret
  155. Asm_SetDr1 ENDP
  156. Asm_SetDr2 PROC
  157.         mov                dr2, ecx
  158.         ret
  159. Asm_SetDr2 ENDP
  160. Asm_SetDr3 PROC
  161.         mov                dr3, ecx
  162.         ret
  163. Asm_SetDr3 ENDP
  164. Asm_SetDr6 PROC nNewDr6:DWORD
  165.         mov eax,nNewDr6
  166.         mov                dr6, eax
  167.         ret
  168. Asm_SetDr6 ENDP
  169. Asm_SetDr7 PROC        nNewDr7:DWORD
  170.         mov eax,nNewDr7
  171.         mov                dr7, eax
  172.         ret
  173. Asm_SetDr7 ENDP
  174. Asm_GetEflags PROC
  175.         pushfd
  176.         pop                eax
  177.         ret
  178. Asm_GetEflags ENDP
  179. Asm_GetIdtBase PROC
  180.         LOCAL        idtr[10]:BYTE
  181.        
  182.         sidt        idtr
  183.         mov                eax, dword PTR idtr[2]
  184.         ret
  185. Asm_GetIdtBase ENDP
  186. Asm_GetIdtLimit PROC
  187.         LOCAL        idtr[10]:BYTE
  188.        
  189.         sidt        idtr
  190.         mov                ax, WORD PTR idtr[0]
  191.         ret
  192. Asm_GetIdtLimit ENDP
  193. Asm_GetGdtBase PROC
  194.         LOCAL        gdtr[10]:BYTE
  195.         sgdt        gdtr
  196.         mov                eax, dword PTR gdtr[2]
  197.         ret
  198. Asm_GetGdtBase ENDP
  199. Asm_GetGdtLimit PROC
  200.         LOCAL        gdtr[10]:BYTE
  201.         sgdt        gdtr
  202.         mov                ax, WORD PTR gdtr[0]
  203.         ret
  204. Asm_GetGdtLimit ENDP
  205. Asm_GetLdtr PROC
  206.         sldt        eax
  207.         ret
  208. Asm_GetLdtr ENDP
  209. Asm_GetTr PROC
  210.         str        eax
  211.         ret
  212. Asm_GetTr ENDP
  213. Asm_SetGdtr                Proc
  214.        
  215.         push        ecx
  216.         shl        edx, 16
  217.         push        edx
  218.        
  219.         lgdt        fword ptr [esp+2]
  220.         pop        eax
  221.         pop        eax
  222.         ret
  223. Asm_SetGdtr        Endp
  224. Asm_SetIdtr                Proc
  225.        
  226.         push        ecx
  227.         shl        edx, 16
  228.         push        edx
  229.         lidt        fword ptr [esp+2]
  230.         pop        eax
  231.         pop        eax
  232.         ret
  233. Asm_SetIdtr        Endp
  234. Vmx_VmxOn Proc LowPart:dword,HighPart:dword
  235.         push HighPart
  236.         push LowPart
  237.         Vmxon qword ptr [esp]
  238.         add esp,8
  239.         ret
  240. Vmx_VmxOn Endp
  241. Vmx_VmxOff Proc
  242.         Vmxoff
  243.         ret
  244. Vmx_VmxOff Endp
  245. Vmx_VmPtrld Proc LowPart:dword,HighPart:dword
  246. ;!!!!!!!!!!!!!!!VMCS!!!!!!!!!!!!!!!!!!!
  247.         push HighPart
  248.         push LowPart
  249.         vmptrld qword ptr [esp]
  250.         add esp,8
  251.         ret
  252. Vmx_VmPtrld endp
  253. Vmx_VmClear Proc LowPart:dword,HighPart:dword
  254. ;!!!!!!!!!!!!!!!VMCS!!!!!!!!!!!!!!!!!!!
  255.         push HighPart
  256.         push LowPart
  257.         vmclear qword ptr [esp]
  258.         add esp,8
  259.         ret
  260. Vmx_VmClear endp
  261. Vmx_VmRead Proc uses ecx Field:dword
  262.         mov eax,Field
  263.         vmread ecx,eax
  264.         mov eax,ecx
  265.         ret
  266. Vmx_VmRead endp
  267. Vmx_VmWrite Proc uses ecx Field:dword,Value:dword
  268.         mov eax,Field
  269.         mov ecx,Value
  270.         vmwrite eax,ecx
  271.         ret
  272. Vmx_VmWrite endp
  273. Vmx_VmCall Proc HyperCallNumber:DWORD
  274.         pushad
  275.         pushfd
  276.         mov eax,HyperCallNumber
  277.         vmcall
  278.        
  279.         popfd
  280.         popad
  281.         ret
  282. Vmx_VmCall endp
  283. Vmx_VmLaunch Proc
  284.         vmlaunch
  285.         ret
  286. Vmx_VmLaunch endp
  287. Vmx_VmResume Proc
  288.         vmresume
  289.         ret
  290. Vmx_VmResume endp
  291. Asm_GetVMXBasic Proc
  292.         push 480h        ;        MSR_IA32_VMX_BASIC
  293.         call Asm_ReadMsr
  294.         ret
  295. Asm_GetVMXBasic endp
  296. Asm_GetCr0Ex Proc
  297.         mov eax,cr0
  298.         ret
  299. Asm_GetCr0Ex endp
  300. Asm_GetCr4Ex Proc
  301.         mov eax,cr4
  302.         ret
  303. Asm_GetCr4Ex endp
  304. Asm_SetCr0Ex Proc nNewCr0:DWORD
  305.         mov eax,nNewCr0
  306.         mov cr0,eax
  307.         ret
  308. Asm_SetCr0Ex endp
  309. Asm_SetCr4Ex Proc nNewCr4:DWORD
  310.         mov eax,nNewCr4
  311.         mov cr4,eax
  312.         ret
  313. Asm_SetCr4Ex endp
  314. Asm_GetEflagsEx Proc
  315.         pushfd
  316.         pop eax
  317.         ret
  318. Asm_GetEflagsEx endp
  319. Asm_GetGuestESP Proc
  320.         mov eax,GuestESP
  321.         ret
  322. Asm_GetGuestESP Endp
  323. Asm_GetGuestReturn Proc
  324.         mov eax,GuestReturn
  325.         ret
  326. Asm_GetGuestReturn Endp
  327. Asm_AfterVMXOff Proc JmpESP:dword,JmpEIP:dword
  328.         mov esp,JmpESP
  329.         jmp JmpEIP
  330.         ret
  331. Asm_AfterVMXOff Endp
  332. Asm_RunToVMCS Proc
  333.         mov eax,[esp]
  334.         mov GuestReturn,eax ;获取返回地址,让vmlaunch后客户机继续执行驱动加载的代码
  335.        
  336.         call SetupVMCS
  337.         ret
  338. Asm_RunToVMCS Endp
  339. Asm_SetupVMCS Proc
  340.         cli
  341.         mov GuestESP,esp
  342.        
  343.         mov EntryEAX,eax
  344.         mov EntryECX,ecx
  345.         mov EntryEDX,edx
  346.         mov EntryEBX,ebx
  347.         mov EntryESP,esp
  348.         mov EntryEBP,ebp
  349.         mov EntryEDI,edi
  350.         mov EntryESI,esi
  351.         pushfd
  352.         pop EntryEflags
  353.        
  354.         call Asm_RunToVMCS
  355.        
  356.         push EntryEflags
  357.         popfd
  358.         mov eax,EntryEAX
  359.         mov ecx,EntryECX
  360.         mov edx,EntryEDX
  361.         mov ebx,EntryEBX
  362.         mov esp,EntryESP
  363.         mov ebp,EntryEBP
  364.         mov esi,EntryESI
  365.         mov edi,EntryEDI
  366.        
  367.         mov esp,GuestESP
  368.         sti
  369.         ret
  370. Asm_SetupVMCS Endp
  371. Asm_VMMEntryPoint Proc
  372.         cli
  373.         push eax
  374.         push ecx
  375.         push edx
  376.         push ebx
  377.         push esp     ;HOST_RSP
  378.         push ebp
  379.         push edi
  380.         push esi
  381.        
  382.         mov [esp-1280h],eax
  383.         mov [esp-1284h],ebx
  384.         call GetGuestRegsAddress
  385.         mov [eax+4h],ecx
  386.         mov [eax+8h],edx
  387.         mov [eax+0Ch],ebx
  388.         mov [eax+10h],esp
  389.         mov [eax+14h],ebp
  390.         mov [eax+18h],esi
  391.         mov [eax+1Ch],edi
  392.         mov ebx,[esp-1280h]
  393.         mov [eax],ebx
  394.         mov eax,[esp-1280h]
  395.         mov ebx,[esp-1284h]
  396.        
  397.         call VMMEntryPoint
  398.        
  399.         pop esi
  400.         pop edi
  401.         pop ebp
  402.         pop esp
  403.         pop ebx
  404.         pop edx
  405.         pop ecx
  406.         pop eax
  407.        
  408.         call GetGuestRegsAddress
  409.         mov ecx,[eax+4h]
  410.         mov edx,[eax+8h]
  411.         mov ebx,[eax+0Ch]
  412.         mov esp,[eax+10h]
  413.         mov ebp,[eax+14h]
  414.         mov esi,[eax+18h]
  415.         mov edi,[eax+1Ch]
  416.         mov eax,[eax]
  417.         sti
  418.         vmresume
  419. Asm_VMMEntryPoint Endp
  420. END
复制代码

还记得前面VMCALL 这里我们要处理下
当需要关闭VT时 我们在虚拟机调用VMCALL 这时进入VMM
我们需要调用VMOFF关闭VT 但关闭VT后EIP是在关闭VT的这里 我们要让它会到调用VMCALL的下一条指令去
  1. void HandleVmCall()
  2. {
  3.         ULONG JmpEIP;
  4.         if (g_GuestRegs.eax == 'SVT')
  5.         {
  6.                 //得到调用VmCall指令的下一句指令地址
  7.                 JmpEIP = g_GuestRegs.eip + Vmx_VmRead(VM_EXIT_INSTRUCTION_LEN);
  8.                 //调用VmxOff
  9.                 Vmx_VmxOff();
  10.                 //设置返回esp和eip
  11.                 Asm_AfterVMXOff(g_GuestRegs.esp,JmpEIP);
  12.                 /*
  13.                 Asm_AfterVMXOff Proc JmpESP:dword,JmpEIP:dword
  14.                         mov esp,JmpESP
  15.                         jmp JmpEIP
  16.                         ret
  17.                 Asm_AfterVMXOff Endp
  18.                 */
  19.         }
  20. }
复制代码

代码注释的很清楚不在多解释
代码来自看雪小宝的教程此文只是此教程的文字版
目前代码只能运行在单核的x86 intel cpu 的系统中
后面会补充在多核x64



   





点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 16:42

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

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