-
-
[原创]64位“最”简VT Demo code 一枚(1)
-
发表于:
2016-1-10 16:45
18414
-
[原创]64位“最”简VT Demo code 一枚(1)
64位“最”简VT Demo code 一枚(1)
“最”简意味着没有实际功能,但代码精简易读,在学习VT时可作参考。
test目录有cpuid.exe,加载编译后的sys后cpuid.exe输出不同。
代码见:https://github.com/DeDf/nbp-0.32-plus
编译说明:
WDK 7.1 “WIN7 x64 Checked Build Environment”,cd进源码目录,bld回车即可;
源码目录有amd64目录,里面放asm文件,配合sources里的:
AMD64_SOURCES=\
vmx-asm.asm \
common-asm.asm \
regs.asm
可以编译asm,所以不要修改amd64目录名。
代码改自nbp-0.32-plus,Copyright holder: Invisible Things Lab
====== newbp.c ======
/*
* Copyright holder: Invisible Things Lab
*/
#include <ntddk.h>
#include "hvm.h"
VOID
DriverUnload (
PDRIVER_OBJECT DriverObject
)
{
if ( HvmSpitOutBluepill () ) // 吐出药丸子
KdPrint (("[NEWBLUEPILL] HvmSpitOutBluepill() failed!\n"));
else
KdPrint (("[NEWBLUEPILL] Unloading finished~\n"));
}
NTSTATUS
DriverEntry (
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
)
{
KdPrint (("\n[NEWBLUEPILL] DriverEntry~\n"));
if (!VmxIsImplemented ())
{
KdPrint (("DriverEntry(): VMX is not supported!\n"));
return STATUS_NOT_SUPPORTED;
}
if ( HvmSwallowBluepill () ) // 吞下药丸子
{
KdPrint (("[NEWBLUEPILL] HvmSwallowBluepill() failed!\n"));
return STATUS_UNSUCCESSFUL;
}
DriverObject->DriverUnload = DriverUnload;
KdPrint (("[NEWBLUEPILL] Initialization finished~\n"));
return STATUS_SUCCESS;
}
VmxIsImplemented ()通过cpuid指令,探测CPU是否支持VMX,
"适用于cpu的intel虚拟化技术叫VT-x,通过VMX架构来实现VT-x"..
HvmSwallowBluepill() 初始化VT,
HvmSpitOutBluepill () 退出VT;
====== hvm.c ======
HvmSwallowBluepill():
在CPU每个核心分别执行CmSubvert;
HvmSpitOutBluepill ():
在CPU每个核心分别执行VmxVmCall (NBP_HYPERCALL_UNLOAD)来退出VT;
====== common-asm.asm ======
CmSubvert 里push了所有通用寄存器,然后把此时的esp作为参数call HvmSubvertCpu;
HvmSubvertCpu()->VmxSetupVMCS()会把这个esp写入VT里的GUEST_RSP,并把CmGuestEip函数地址写入VT里的GUEST_RIP;
CmGuestEip里会依序弹出所有的通用寄存器,然后ret.
当__vmx_vmlaunch()并且从VMM Exit到VM中,换句话说VT初始化完成第一次回到OS中,(VMM - VM monitor)
此时esp和eip会被CPU设置为GUEST_RSP和GUEST_RIP,
那么CmSubvert和CmGuestEip分别push和pop了通用寄存器,并且保证了栈平衡,VMM里做了什么处理,对OS是透明了。
====== hvm.c ======
HvmSubvertCpu()
关于VT开启的过程和各控制域后面说,先把外面的脉络理清楚;
这里申请了三块内存,存放于以下结构里,方便卸载时释放,每个CPU核心一个;
typedef struct _CPU
{
PVOID OriginalVmcs; // VMCS结构,每个guest OS 一个
PVOID OriginaVmxonR; // Vmxon结构,每个CPU核心一个
PVOID VMM_Stack; // VMM栈
} CPU, *PCPU;
其中前两者是用MmAllocateContiguousMemory申请的内存,貌似意味着需要4K对齐和物理上连续;
栈是向下增长的,所以这样:
VMM_Stack = (ULONG_PTR)pCpu->VMM_Stack + 2 * PAGE_SIZE - 8;
这个栈是当VMM Entry时的栈,由VmxSetupVMCS设置的:
// HOST_RSP与HOST_RIP决定进入VMM的地址
__vmx_vmwrite (HOST_RSP, VMM_Stack);
__vmx_vmwrite (HOST_RIP, (ULONG64) VmxVmexitHandler);
VmxVmexitHandler是进入到VMM时的eip,位于vmx-asm.asm中,需要注意的是栈要平衡。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课