- 注册时间
- 2011-3-6
- 最后登录
- 1970-1-1
该用户从未签到
|
一共有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 nNewDr6:DWORD
- mov eax,nNewDr6
- mov dr6, eax
- ret
- Asm_SetDr6 ENDP
- Asm_SetDr7 PROC nNewDr7:DWORD
- 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 HyperCallNumber:DWORD
- 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 nNewCr0:DWORD
- mov eax,nNewCr0
- mov cr0,eax
- ret
- Asm_SetCr0Ex endp
- Asm_SetCr4Ex Proc nNewCr4:DWORD
- 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
|
|