Intel VT学习笔记(六)—— VM-Exit Handler
Intel VT學(xué)習(xí)筆記(六)—— VM-Exit Handler
- Reutrn To DriverEntry
- VM-Exit Handler
- External interrupt
- I/O instruction
- Control-register accesses
- CPUID
- VMCALL
- 完整代碼
- 參考資料
Reutrn To DriverEntry
描述:當開啟VT后,就可以從DriverEntry中返回了,但應(yīng)該怎么做呢?
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path) {DbgPrint("Driver load. \r\n");pDriver->DriverUnload = DriverUnload;StartVirtualTechnology(); //開啟VT//=========================================//how do I get here?//=========================================return STATUS_SUCCESS; }實現(xiàn)思路:
代碼實現(xiàn)(在Guest中執(zhí)行INT 3或VMCALL都可以):
//driver.c NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path) {DbgPrint("Driver load. \r\n");pDriver->DriverUnload = DriverUnload;__asm{pushadpushfdmov g_ret_esp, espmov g_ret_eip, offset RET_EIP}StartVirtualTechnology(); //開啟VTRET_EIP:__asm{popfdpopad}Log("Return To DriverEntry .", 0);return STATUS_SUCCESS; } //exithandler.c extern ULONG g_ret_esp; extern ULONG g_ret_eip;GUEST_REGS g_GuestRegs;static void VMMEntryPointEbd(void) {ULONG ExitReason;ExitReason = Vmx_VmRead(VM_EXIT_REASON);Log("ExitReason", ExitReason);g_GuestRegs.esp = Vmx_VmRead(GUEST_RSP);g_GuestRegs.eip = Vmx_VmRead(GUEST_RIP);Log("g_GuestRegs.esp", g_GuestRegs.esp);Log("g_GuestRegs.eip", g_GuestRegs.eip);__asm{mov esp, g_ret_espjmp g_ret_eip} }執(zhí)行結(jié)果:
可以看到,CPU已經(jīng)成功回到了DriverEntry,并能夠關(guān)閉VT以及卸載驅(qū)動。
VM-Exit Handler
描述:當Guest觸發(fā)VM-Exit時,會進入Host進行處理。如果需要在Return To DriverEntry后使系統(tǒng)保持VT模式,則需要將返回代碼寫在Guest中,并在VM-Exit Handler中對各類VM-Exit事件進行處理。
代碼實現(xiàn):
//vtsystem.c ... void __declspec(naked) GuestEntry() {__asm {mov ax, esmov es, axmov ax, dsmov ds, axmov ax, fsmov fs, axmov ax, gsmov gs, axmov ax, ssmov ss, axmov esp, g_ret_espjmp g_ret_eip} } ... //exithandler.c ... static void VMMEntryPointEbd(void) {ULONG ExitReason;ULONG ExitInstructionLength;ULONG GuestResumeEIP;ExitReason = Vmx_VmRead(VM_EXIT_REASON); //獲取退出碼ExitInstructionLength = Vmx_VmRead(VM_EXIT_INSTRUCTION_LEN); //獲取指令長度Log("ExitReason", ExitReason);g_GuestRegs.eflags = Vmx_VmRead(GUEST_RFLAGS);g_GuestRegs.esp = Vmx_VmRead(GUEST_RSP);g_GuestRegs.eip = Vmx_VmRead(GUEST_RIP);Log("g_GuestRegs.eflags", g_GuestRegs.eflags);Log("g_GuestRegs.esp", g_GuestRegs.esp);Log("g_GuestRegs.eip", g_GuestRegs.eip);switch(ExitReason){case ...: //需要處理的退出碼//處理程序break;...default:Log("not handled reason: %p", ExitReason);__asm int 3;break;}__asm INT 3; }void __declspec(naked) VMMEntryPoint(void) {__asm{//需要設(shè)置fs和gs,否則無法正常運行mov ax, fsmov fs, axmov ax, gsmov gs, ax}Log("VM Exit", 0);//盡量不要在裸函數(shù)中定義局部變量,或?qū)崿F(xiàn)太多功能,最好封裝成函數(shù)VMMEntryPointEbd(); } ...External interrupt
描述:通過設(shè)置,可以使外部中斷觸發(fā)VM-Exit。
令人感到奇怪的是,明明在設(shè)置VMCS字段的時候已經(jīng)將TF位置0了,卻仍然捕捉到了外部中斷。
Vmx_VmWrite(GUEST_RFLAGS, Asm_GetEflags() & ~0x200); //cli運行結(jié)果:
由于筆剛接觸這一塊,是跟著周壑老師的視頻做的實驗,而周壑老師做實驗的時候并沒有遇到01錯誤,因此一下子給筆者整不會了,折磨了很久,谷歌百度均無果,最終通過查手冊解決(手冊YYDS),原來是控制寄存器的設(shè)置出了問題。
查手冊卷3附錄C,退出碼1對應(yīng)的信息是外部中斷,原因是控制域中相應(yīng)位被設(shè)置。
翻閱控制域相關(guān)部分(詳見24.6.1),在「Pin-Based VM-Execution Controls」找到關(guān)于外部中斷的詳細說明。
這里說,如果IA32_VMX_PINBASED_CTLS MSR的第0位為1,表示外部中斷將觸發(fā)VM-Exit,并且ELFAGS的TF位失效。
找到原因了,那么接下來,只要在設(shè)置IA32_VMX_PINBASED_CTLS MSR的時候?qū)⒌?位置0即可。
當然,如果需要手動處理外部中斷,可以忽略這一步。
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 */if (MSR_IA32_VMX_PINBASED_CTLS == Msr){Ctl &= ~1;} }運行結(jié)果:
可以看到,退出碼01已經(jīng)消失了,此時出現(xiàn)了一個新的退出碼1E。
I/O instruction
描述:訪問I/O時觸發(fā)了VM-Exit,對應(yīng)退出碼1E。
退出碼1E的出現(xiàn)也是在意料之外的,和01類似,也是由于MSR寄存器的設(shè)置出現(xiàn)了問題。
從手冊對該退出碼的描述可以看到,除了訪問I/O,還需要滿足兩個條件。
第二個條件不太理解是什么意思,但是第一個條件我們可以手動給他取消。
關(guān)于「use I/O bitmaps」和「unconditional I/O exiting」標志位可查閱Intel手冊卷3第24.6.2小節(jié),是IA32_VMX_PROCBASED_CTLS MSR寄存器的第24比特位和第25比特位。。
目前無需了解其具體含義,把它們?nèi)恐?先。
執(zhí)行結(jié)果:
好了,現(xiàn)在退出碼1E也消失了,捕獲到的退出碼變成了1C,總算可以進入正題了。
Control-register accesses
描述:當Guest試圖使用控制寄存器時會觸發(fā)該事件,對應(yīng)的退出碼為0x1C。
處理方式:當Guest試圖使用控制寄存器,并觸發(fā)VM-Exit來到Host后,Host通過讀取相應(yīng)的信息,幫助Guest完成對應(yīng)的功能,然后回到觸發(fā)該事件的下一句指令。
ExitQualification = Vmx_VmRead(EXIT_QUALIFICATION);關(guān)于「Control-register accesses」錯誤的具體信息可參考Intel開發(fā)手冊卷3第27.2小節(jié)。
值得注意的是,在實現(xiàn)Handler的過程中,只攔截Cr3即可。
具體思路:
代碼實現(xiàn):
void HandleCrAccess() {ULONG movcrControlRegister;ULONG movcrAccessType;ULONG movcrOperandType; //只是讀了,沒有使用,通常都是寄存器ULONG movcrGeneralPurposeRegister;ULONG movcrLMSWSourceData;ULONG ExitQualification;ExitQualification = Vmx_VmRead(EXIT_QUALIFICATION); //獲取具體信息movcrControlRegister = (ExitQualification & 0x0000000F); //控制寄存器下標movcrAccessType = ((ExitQualification & 0x00000030) >> 4); //讀/寫movcrOperandType = ((ExitQualification & 0x00000040) >> 6); //寄存器/內(nèi)存movcrGeneralPurposeRegister = ((ExitQualification & 0x00000F00) >> 8); //寄存器下標if (movcrControlRegister != 3) { // not for cr3__asm int 3}if (movcrAccessType == 0) { // CR3 <-- reg32Vmx_VmWrite(GUEST_CR3, *(PULONG)((ULONG)&g_GuestRegs + 4 * movcrGeneralPurposeRegister));}else { // reg32 <-- CR3*(PULONG)((ULONG)&g_GuestRegs + 4 * movcrGeneralPurposeRegister) = Vmx_VmRead(GUEST_CR3);} }執(zhí)行結(jié)果:
可以看到系統(tǒng)在不斷訪問控制寄存器,讓我們看看是誰干的。
破案了,原來是線程切換的時候訪問了Cr3。
由于系統(tǒng)在不斷地切換線程,因此也就在不斷地輸出調(diào)試信息,這個時候系統(tǒng)會處于假卡死狀態(tài),無法正常操作。
把輸出調(diào)試信息的代碼注釋掉之后,系統(tǒng)就變得流暢了起來,但是這并不代表已經(jīng)完全沒問題了。
當進行特定操作時,仍然會觸發(fā)其他原因?qū)е碌腣M-Exit,例如當打開一個進程時,會觸發(fā)退出碼0A(CPUID)。
CPUID
描述:匯編指令,用于獲取CPU的相關(guān)信息,當Guest調(diào)用該指令時,會觸發(fā)VM-Exit信號。
處理方法:在Host中模擬執(zhí)行,并返回結(jié)果。
void HandleCPUID() {//特殊處理,用于測試VT是否開啟,注意保證參數(shù)的獨立性。if (g_GuestRegs.eax == 'Mini'){g_GuestRegs.ebx = 0x88888888;g_GuestRegs.ecx = 0x11111111;g_GuestRegs.edx = 0x12345678;}//正常情況,替Guest模擬執(zhí)行CPUIDelse Asm_CPUID(g_GuestRegs.eax, &g_GuestRegs.eax, &g_GuestRegs.ebx, &g_GuestRegs.ecx, &g_GuestRegs.edx); }執(zhí)行結(jié)果(CPUID的調(diào)用頻次不高,開啟調(diào)試信息問題不大):
可以發(fā)現(xiàn)已經(jīng)能夠正常處理CPUID指令,然后將EAX改為「Mini」的ASCII碼,再調(diào)用CPUID試試。
ECX、EDX、EBX返回的結(jié)果正是Handle處理的結(jié)果,說明現(xiàn)在系統(tǒng)確實是處于VT模式。
VMCALL
描述:執(zhí)行VMCALL指令時,能夠觸發(fā)一次VM-Exit。
使用場景:當需要退出VT模式時,如果直接調(diào)用VMXOFF指令,由于Guest將沒有權(quán)限執(zhí)行,因此將會出錯??尚械乃悸肥窍仁褂肰MCALL切換到VMX root模式,由Host來執(zhí)行退出部分的代碼。
代碼實現(xiàn):
ULONG g_vmcall_arg; ULONG g_stop_esp, g_stop_eip;void HandleVmCall() {if (g_vmcall_arg == 'SVT'){Vmx_VmClear(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart);Vmx_VmxOff();__asm {mov esp, g_stop_espjmp g_stop_eip}}else {__asm int 3} }處理完這幾個退出碼之后,基本就初步實現(xiàn)了一個最小VT框架。如果后續(xù)遇到其它退出碼,可再通過查手冊解決。
完整代碼
//vtasm.h #ifndef VTASM_H #define VTASM_Htypedef union {struct{unsigned SSE3 : 1;unsigned PCLMULQDQ : 1;unsigned DTES64 : 1;unsigned MONITOR : 1;unsigned DS_CPL : 1;unsigned VMX : 1;unsigned SMX : 1;unsigned EIST : 1;unsigned TM2 : 1;unsigned SSSE3 : 1;unsigned Reserved : 22;};}_CPUID_ECX;typedef struct _IA32_FEATURE_CONTROL_MSR {unsigned Lock : 1; // Bit 0 is the lock bit - cannot be modified once lock is setunsigned Reserved1 : 1; // Undefinedunsigned EnableVmxon : 1; // Bit 2. If this bit is clear, VMXON causes a general protection exceptionunsigned Reserved2 : 29; // Undefinedunsigned Reserved3 : 32; // Undefined} IA32_FEATURE_CONTROL_MSR;typedef struct _VMX_BASIC_MSR {unsigned RevId : 32;unsigned szVmxOnRegion : 12;unsigned ClearBit : 1;unsigned Reserved : 3;unsigned PhysicalWidth : 1;unsigned DualMonitor : 1;unsigned MemoryType : 4;unsigned VmExitInformation : 1;unsigned Reserved2 : 9; } VMX_BASIC_MSR, * PVMX_BASIC_MSR;typedef union {struct{unsigned PE : 1;unsigned MP : 1;unsigned EM : 1;unsigned TS : 1;unsigned ET : 1;unsigned NE : 1;unsigned Reserved_1 : 10;unsigned WP : 1;unsigned Reserved_2 : 1;unsigned AM : 1;unsigned Reserved_3 : 10;unsigned NW : 1;unsigned CD : 1;unsigned PG : 1;//unsigned Reserved_64:32;};}_CR0;typedef union {struct {unsigned VME : 1;unsigned PVI : 1;unsigned TSD : 1;unsigned DE : 1;unsigned PSE : 1;unsigned PAE : 1;unsigned MCE : 1;unsigned PGE : 1;unsigned PCE : 1;unsigned OSFXSR : 1;unsigned PSXMMEXCPT : 1;unsigned UNKONOWN_1 : 1; //These are zerounsigned UNKONOWN_2 : 1; //These are zerounsigned VMXE : 1; //It's zero in normalunsigned Reserved : 18; //These are zero//unsigned Reserved_64:32;}; }_CR4;typedef union {struct{unsigned CF : 1;unsigned Unknown_1 : 1; //Always 1unsigned PF : 1;unsigned Unknown_2 : 1; //Always 0unsigned AF : 1;unsigned Unknown_3 : 1; //Always 0unsigned ZF : 1;unsigned SF : 1;unsigned TF : 1;unsigned IF : 1;unsigned DF : 1;unsigned OF : 1;unsigned TOPL : 2;unsigned NT : 1;unsigned Unknown_4 : 1;unsigned RF : 1;unsigned VM : 1;unsigned AC : 1;unsigned VIF : 1;unsigned VIP : 1;unsigned ID : 1;unsigned Reserved : 10; //Always 0//unsigned Reserved_64:32; //Always 0}; }_EFLAGS;void Asm_CPUID(ULONG uFn, PULONG uRet_EAX, PULONG uRet_EBX, PULONG uRet_ECX, PULONG uRet_EDX);void Asm_IN(ULONG uRet_EAX, ULONG uPort);ULONG64 Asm_ReadMsr(ULONG uIndex);ULONG Asm_GetEflags(); ULONG Asm_GetCs(); ULONG Asm_GetDs(); ULONG Asm_GetEs(); ULONG Asm_GetFs(); ULONG Asm_GetGs(); ULONG Asm_GetSs(); ULONG Asm_GetTr();ULONG Asm_GetGdtBase(); ULONG Asm_GetIdtBase(); ULONG Asm_GetGdtLimit(); ULONG Asm_GetIdtLimit();ULONG Asm_GetCr0(); ULONG Asm_GetCr3(); ULONG Asm_GetCr4();void Asm_SetCr4(ULONG uNewCr4);void Vmx_VmxOn(ULONG LowPart, ULONG HighPart); void Vmx_VmxOff();void Vmx_VmClear(ULONG LowPart, ULONG HighPart); void Vmx_VmPtrld(ULONG LowPart, ULONG HighPart); ULONG Vmx_VmRead(ULONG uField); void Vmx_VmWrite(ULONG uField, ULONG uValue); void Vmx_VmLaunch(); void Vmx_VmCall();#endif //vtasm.asm .686p .model flat, stdcall option casemap:none.data.codeAsm_CPUID Proc uses ebx esi edi fn:dword, ret_eax:dword, ret_ebx:dword, ret_ecx:dword, ret_edx:dwordmov eax, fncpuidmov esi, ret_eaxmov dword ptr [esi], eaxmov esi, ret_ebxmov dword ptr [esi], ebxmov esi, ret_ecxmov dword ptr [esi], ecxmov esi, ret_edxmov dword ptr [esi], edxret Asm_CPUID EndpAsm_IN Proc uRet_EAX:dword, uPort:dwordmov eax, uRet_EAXmov edx, uPortin eax, dx Asm_IN EndpAsm_ReadMsr Proc Index:dwordmov ecx,Indexrdmsrret Asm_ReadMsr EndpAsm_GetCr0 Procmov eax, cr0ret Asm_GetCr0 EndpAsm_GetCr3 Procmov eax, cr3ret Asm_GetCr3 EndpAsm_GetCr4 Procmov eax, cr4ret Asm_GetCr4 EndpAsm_SetCr4 Proc NewCr4:dwordmov eax,NewCr4mov cr4, eaxret Asm_SetCr4 EndpVmx_VmxOn Proc LowPart:dword,HighPart:dwordpush HighPartpush LowPartVmxon qword ptr [esp]add esp,8ret Vmx_VmxOn EndpVmx_VmxOff ProcVmxoffret Vmx_VmxOff EndpAsm_GetEflags PROCpushfdpop eaxret Asm_GetEflags ENDPVmx_VmClear Proc LowPart:dword,HighPart:dwordpush HighPartpush LowPartvmclear qword ptr [esp]add esp,8ret Vmx_VmClear endpVmx_VmPtrld Proc LowPart:dword,HighPart:dwordpush HighPartpush LowPartvmptrld qword ptr [esp]add esp,8ret Vmx_VmPtrld endpVmx_VmRead Proc uses ecx Field:dwordmov eax,Fieldvmread ecx,eaxmov eax,ecxret Vmx_VmRead endpVmx_VmWrite Proc uses ecx Field:dword,Value:dwordmov eax,Fieldmov ecx,Valuevmwrite eax,ecxret Vmx_VmWrite endpAsm_GetCs PROCmov eax, csret Asm_GetCs ENDPAsm_GetDs PROCmov eax, dsret Asm_GetDs ENDPAsm_GetEs PROCmov eax, esret Asm_GetEs ENDPAsm_GetSs PROCmov eax, ssret Asm_GetSs ENDPAsm_GetFs PROCmov eax, fsret Asm_GetFs ENDPAsm_GetGs PROCmov eax, gsret Asm_GetGs ENDPAsm_GetTr PROCstr eaxret Asm_GetTr ENDPAsm_GetGdtBase PROCLOCAL gdtr[10]:BYTEsgdt gdtrmov eax, dword PTR gdtr[2]ret Asm_GetGdtBase ENDPAsm_GetGdtLimit PROCLOCAL gdtr[10]:BYTEsgdt gdtrmov ax, WORD PTR gdtr[0]ret Asm_GetGdtLimit ENDPAsm_GetIdtBase PROCLOCAL idtr[10]:BYTEsidt idtrmov eax, dword PTR idtr[2]ret Asm_GetIdtBase ENDPAsm_GetIdtLimit PROCLOCAL idtr[10]:BYTEsidt idtrmov ax, WORD PTR idtr[0]ret Asm_GetIdtLimit ENDPVmx_VmLaunch Procvmlaunchret Vmx_VmLaunch endpVmx_VmCall Procvmcallret Vmx_VmCall endpEND //vtsystem.h #ifndef VTSYSTEM_H #define VTSYSTEM_H #include <ntddk.h>/*MSR definition*/ #define MSR_IA32_FEATURE_CONTROL 0x03a #define MSR_IA32_VMX_BASIC 0x480 #define MSR_IA32_VMX_PINBASED_CTLS 0x481 #define MSR_IA32_VMX_PROCBASED_CTLS 0x482 #define MSR_IA32_VMX_EXIT_CTLS 0x483 #define MSR_IA32_VMX_ENTRY_CTLS 0x484#define MSR_IA32_SYSENTER_CS 0x174 #define MSR_IA32_SYSENTER_ESP 0x175 #define MSR_IA32_SYSENTER_EIP 0x176 #define MSR_IA32_DEBUGCTL 0x1d9//VMX Exit Reasons #define EXIT_REASON_CPUID 10 #define EXIT_REASON_VMCALL 18 #define EXIT_REASON_CR_ACCESS 28typedef struct _VMX_CPU {PVOID pVMXONRegion;PHYSICAL_ADDRESS pVMXONRegion_PA;PVOID pVMCSRegion;PHYSICAL_ADDRESS pVMCSRegion_PA;PVOID pStack;BOOLEAN bVTStartSuccess; }VMX_CPU, * PVMX_CPU;/* VMCS Encordings */ enum {VIRTUAL_PROCESSOR_ID = 0x00000000,POSTED_INTR_NV = 0x00000002,GUEST_ES_SELECTOR = 0x00000800,GUEST_CS_SELECTOR = 0x00000802,GUEST_SS_SELECTOR = 0x00000804,GUEST_DS_SELECTOR = 0x00000806,GUEST_FS_SELECTOR = 0x00000808,GUEST_GS_SELECTOR = 0x0000080a,GUEST_LDTR_SELECTOR = 0x0000080c,GUEST_TR_SELECTOR = 0x0000080e,GUEST_INTR_STATUS = 0x00000810,HOST_ES_SELECTOR = 0x00000c00,HOST_CS_SELECTOR = 0x00000c02,HOST_SS_SELECTOR = 0x00000c04,HOST_DS_SELECTOR = 0x00000c06,HOST_FS_SELECTOR = 0x00000c08,HOST_GS_SELECTOR = 0x00000c0a,HOST_TR_SELECTOR = 0x00000c0c,IO_BITMAP_A = 0x00002000,IO_BITMAP_A_HIGH = 0x00002001,IO_BITMAP_B = 0x00002002,IO_BITMAP_B_HIGH = 0x00002003,MSR_BITMAP = 0x00002004,MSR_BITMAP_HIGH = 0x00002005,VM_EXIT_MSR_STORE_ADDR = 0x00002006,VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007,VM_EXIT_MSR_LOAD_ADDR = 0x00002008,VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009,VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a,VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b,TSC_OFFSET = 0x00002010,TSC_OFFSET_HIGH = 0x00002011,VIRTUAL_APIC_PAGE_ADDR = 0x00002012,VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013,APIC_ACCESS_ADDR = 0x00002014,APIC_ACCESS_ADDR_HIGH = 0x00002015,POSTED_INTR_DESC_ADDR = 0x00002016,POSTED_INTR_DESC_ADDR_HIGH = 0x00002017,EPT_POINTER = 0x0000201a,EPT_POINTER_HIGH = 0x0000201b,EOI_EXIT_BITMAP0 = 0x0000201c,EOI_EXIT_BITMAP0_HIGH = 0x0000201d,EOI_EXIT_BITMAP1 = 0x0000201e,EOI_EXIT_BITMAP1_HIGH = 0x0000201f,EOI_EXIT_BITMAP2 = 0x00002020,EOI_EXIT_BITMAP2_HIGH = 0x00002021,EOI_EXIT_BITMAP3 = 0x00002022,EOI_EXIT_BITMAP3_HIGH = 0x00002023,VMREAD_BITMAP = 0x00002026,VMWRITE_BITMAP = 0x00002028,XSS_EXIT_BITMAP = 0x0000202C,XSS_EXIT_BITMAP_HIGH = 0x0000202D,GUEST_PHYSICAL_ADDRESS = 0x00002400,GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401,VMCS_LINK_POINTER = 0x00002800,VMCS_LINK_POINTER_HIGH = 0x00002801,GUEST_IA32_DEBUGCTL = 0x00002802,GUEST_IA32_DEBUGCTL_HIGH = 0x00002803,GUEST_IA32_PAT = 0x00002804,GUEST_IA32_PAT_HIGH = 0x00002805,GUEST_IA32_EFER = 0x00002806,GUEST_IA32_EFER_HIGH = 0x00002807,GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808,GUEST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002809,GUEST_PDPTR0 = 0x0000280a,GUEST_PDPTR0_HIGH = 0x0000280b,GUEST_PDPTR1 = 0x0000280c,GUEST_PDPTR1_HIGH = 0x0000280d,GUEST_PDPTR2 = 0x0000280e,GUEST_PDPTR2_HIGH = 0x0000280f,GUEST_PDPTR3 = 0x00002810,GUEST_PDPTR3_HIGH = 0x00002811,GUEST_BNDCFGS = 0x00002812,GUEST_BNDCFGS_HIGH = 0x00002813,HOST_IA32_PAT = 0x00002c00,HOST_IA32_PAT_HIGH = 0x00002c01,HOST_IA32_EFER = 0x00002c02,HOST_IA32_EFER_HIGH = 0x00002c03,HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04,HOST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002c05,PIN_BASED_VM_EXEC_CONTROL = 0x00004000,CPU_BASED_VM_EXEC_CONTROL = 0x00004002,EXCEPTION_BITMAP = 0x00004004,PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,CR3_TARGET_COUNT = 0x0000400a,VM_EXIT_CONTROLS = 0x0000400c,VM_EXIT_MSR_STORE_COUNT = 0x0000400e,VM_EXIT_MSR_LOAD_COUNT = 0x00004010,VM_ENTRY_CONTROLS = 0x00004012,VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,VM_ENTRY_INTR_INFO_FIELD = 0x00004016,VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,VM_ENTRY_INSTRUCTION_LEN = 0x0000401a,TPR_THRESHOLD = 0x0000401c,SECONDARY_VM_EXEC_CONTROL = 0x0000401e,PLE_GAP = 0x00004020,PLE_WINDOW = 0x00004022,VM_INSTRUCTION_ERROR = 0x00004400,VM_EXIT_REASON = 0x00004402,VM_EXIT_INTR_INFO = 0x00004404,VM_EXIT_INTR_ERROR_CODE = 0x00004406,IDT_VECTORING_INFO_FIELD = 0x00004408,IDT_VECTORING_ERROR_CODE = 0x0000440a,VM_EXIT_INSTRUCTION_LEN = 0x0000440c,VMX_INSTRUCTION_INFO = 0x0000440e,GUEST_ES_LIMIT = 0x00004800,GUEST_CS_LIMIT = 0x00004802,GUEST_SS_LIMIT = 0x00004804,GUEST_DS_LIMIT = 0x00004806,GUEST_FS_LIMIT = 0x00004808,GUEST_GS_LIMIT = 0x0000480a,GUEST_LDTR_LIMIT = 0x0000480c,GUEST_TR_LIMIT = 0x0000480e,GUEST_GDTR_LIMIT = 0x00004810,GUEST_IDTR_LIMIT = 0x00004812,GUEST_ES_AR_BYTES = 0x00004814,GUEST_CS_AR_BYTES = 0x00004816,GUEST_SS_AR_BYTES = 0x00004818,GUEST_DS_AR_BYTES = 0x0000481a,GUEST_FS_AR_BYTES = 0x0000481c,GUEST_GS_AR_BYTES = 0x0000481e,GUEST_LDTR_AR_BYTES = 0x00004820,GUEST_TR_AR_BYTES = 0x00004822,GUEST_INTERRUPTIBILITY_INFO = 0x00004824,GUEST_ACTIVITY_STATE = 0X00004826,GUEST_SYSENTER_CS = 0x0000482A,VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,HOST_IA32_SYSENTER_CS = 0x00004c00,CR0_GUEST_HOST_MASK = 0x00006000,CR4_GUEST_HOST_MASK = 0x00006002,CR0_READ_SHADOW = 0x00006004,CR4_READ_SHADOW = 0x00006006,CR3_TARGET_VALUE0 = 0x00006008,CR3_TARGET_VALUE1 = 0x0000600a,CR3_TARGET_VALUE2 = 0x0000600c,CR3_TARGET_VALUE3 = 0x0000600e,EXIT_QUALIFICATION = 0x00006400,GUEST_LINEAR_ADDRESS = 0x0000640a,GUEST_CR0 = 0x00006800,GUEST_CR3 = 0x00006802,GUEST_CR4 = 0x00006804,GUEST_ES_BASE = 0x00006806,GUEST_CS_BASE = 0x00006808,GUEST_SS_BASE = 0x0000680a,GUEST_DS_BASE = 0x0000680c,GUEST_FS_BASE = 0x0000680e,GUEST_GS_BASE = 0x00006810,GUEST_LDTR_BASE = 0x00006812,GUEST_TR_BASE = 0x00006814,GUEST_GDTR_BASE = 0x00006816,GUEST_IDTR_BASE = 0x00006818,GUEST_DR7 = 0x0000681a,GUEST_RSP = 0x0000681c,GUEST_RIP = 0x0000681e,GUEST_RFLAGS = 0x00006820,GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822,GUEST_SYSENTER_ESP = 0x00006824,GUEST_SYSENTER_EIP = 0x00006826,HOST_CR0 = 0x00006c00,HOST_CR3 = 0x00006c02,HOST_CR4 = 0x00006c04,HOST_FS_BASE = 0x00006c06,HOST_GS_BASE = 0x00006c08,HOST_TR_BASE = 0x00006c0a,HOST_GDTR_BASE = 0x00006c0c,HOST_IDTR_BASE = 0x00006c0e,HOST_IA32_SYSENTER_ESP = 0x00006c10,HOST_IA32_SYSENTER_EIP = 0x00006c12,HOST_RSP = 0x00006c14,HOST_RIP = 0x00006c16, };typedef struct _GUEST_REGS {ULONG eax;ULONG ecx;ULONG edx;ULONG ebx;ULONG esp;ULONG ebp;ULONG esi;ULONG edi;ULONG eip;ULONG eflags; }GUEST_REGS, * PGUEST_REGS;extern VMX_CPU g_VMXCPU;//檢查當前處理器是否支持VT BOOLEAN IsVTEnabled(); //開啟VT NTSTATUS StartVirtualTechnology(); //關(guān)閉VT NTSTATUS StopVirtualTechnology();#define Log(message,value) {{KdPrint(("[MinVT] %-40s [%p]\n",message,value));}}#endif //vtsystem.c #include "vtsystem.h" #include "vtasm.h" #include "exithandler.h"extern ULONG g_back_esp; extern ULONG g_back_eip;VMX_CPU g_VMXCPU;BOOLEAN IsVTEnabled() {ULONG uRet_EAX, uRet_ECX, uRet_EDX, uRet_EBX;_CPUID_ECX uCPUID;_CR0 uCr0;_CR4 uCr4;IA32_FEATURE_CONTROL_MSR msr;//1. CPUIDAsm_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已經(jīng)開啟了VT!", 0);Log("可能是別的驅(qū)動已經(jīng)占用了VT,你必須關(guān)閉它后才能開啟。", 0);return FALSE;}Log("SUCCESS:這個CPU支持VT!", 0);return TRUE; }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 */if (MSR_IA32_VMX_PINBASED_CTLS == Msr) //關(guān)閉外部中斷信號{Ctl &= ~1;}if (MSR_IA32_VMX_PROCBASED_CTLS == Msr) //關(guān)閉I/O訪問信號{Ctl &= ~0x03000000;}return Ctl; }static ULONG GetSegBase(ULONG Select) {ULONG GdtBase = Asm_GetGdtBase();ULONGLONG Descriptor = *(PULONGLONG)(GdtBase + Select);ULONG Base = 0;Base |= (Descriptor & 0xff00000000000000) >> 32;Base |= (Descriptor & 0x000000ff00000000) >> 16;Base |= (Descriptor & 0x00000000ffff0000) >> 16;return Base; }static ULONG GetSegLimit(ULONG Select) {ULONG GdtBase = Asm_GetGdtBase();ULONGLONG Descriptor = *(PULONGLONG)(GdtBase + Select);ULONG Limit = 0;Limit |= (Descriptor & 0x000f000000000000) >> 32;Limit |= Descriptor & 0x000000000000ffff;//if Desc.G == 1 ? 4kb : byteif (Descriptor & 0x0080000000000000){Limit <<= 12;Limit |= 0xfff;}return Limit; }static ULONG GetSegAR(ULONG Select) {ULONG GdtBase = Asm_GetGdtBase();ULONGLONG Descriptor = *(PULONGLONG)(GdtBase + Select);ULONG AR = 0;AR |= (Descriptor & 0x00f0ff0000000000) >> 40;return AR; }void __declspec(naked) GuestEntry() {__asm {mov ax, esmov es, axmov ax, dsmov ds, axmov ax, fsmov fs, axmov ax, gsmov gs, axmov ax, ssmov ss, axmov esp, g_back_espjmp g_back_eip} }void SetupVMCS() {ULONG GdtBase, IdtBase;GdtBase = Asm_GetGdtBase();IdtBase = Asm_GetIdtBase();//// 1.Guest State Area//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() & ~0x200); //cliVmx_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);// 重要的段寄存器信息需要在進入Guest前加載Vmx_VmWrite(GUEST_CS_AR_BYTES, GetSegAR(Asm_GetCs() & 0xFFF8));Vmx_VmWrite(GUEST_CS_BASE, GetSegBase(Asm_GetCs() & 0xFFF8));Vmx_VmWrite(GUEST_CS_LIMIT, GetSegLimit(Asm_GetCs() & 0xFFF8));Vmx_VmWrite(GUEST_TR_AR_BYTES, GetSegAR(Asm_GetTr() & 0xFFF8));Vmx_VmWrite(GUEST_TR_BASE, GetSegBase(Asm_GetTr() & 0xFFF8));Vmx_VmWrite(GUEST_TR_LIMIT, GetSegLimit(Asm_GetTr() & 0xFFF8));// 其他寄存器可在進入Guest后加載,先將屬性的第16位置1,即不可用狀態(tài)Vmx_VmWrite(GUEST_ES_AR_BYTES, 0x10000);Vmx_VmWrite(GUEST_FS_AR_BYTES, 0x10000);Vmx_VmWrite(GUEST_DS_AR_BYTES, 0x10000);Vmx_VmWrite(GUEST_SS_AR_BYTES, 0x10000);Vmx_VmWrite(GUEST_GS_AR_BYTES, 0x10000);Vmx_VmWrite(GUEST_LDTR_AR_BYTES, 0x10000);// CS、ESP、EIPVmx_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// GDTRVmx_VmWrite(GUEST_GDTR_BASE, GdtBase);Vmx_VmWrite(GUEST_GDTR_LIMIT, Asm_GetGdtLimit());// LDTRVmx_VmWrite(GUEST_IDTR_BASE, IdtBase);Vmx_VmWrite(GUEST_IDTR_LIMIT, Asm_GetIdtLimit());Vmx_VmWrite(GUEST_RSP, ((ULONG)g_VMXCPU.pStack) + 0x1000); // Guest 臨時棧Vmx_VmWrite(GUEST_RIP, (ULONG)GuestEntry); // 客戶機的入口點// Link Shadow VMCSVmx_VmWrite(VMCS_LINK_POINTER, 0xffffffff);Vmx_VmWrite(VMCS_LINK_POINTER_HIGH, 0xffffffff);//// 2.Host State Area//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);Vmx_VmWrite(HOST_TR_BASE, GetSegBase(Asm_GetTr() & 0xFFF8));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); // KiFastCallEntryVmx_VmWrite(HOST_RSP, ((ULONG)g_VMXCPU.pStack) + 0x2000); //Host 臨時棧Vmx_VmWrite(HOST_RIP, (ULONG)VMMEntryPoint); //這里定義我們的VMM處理程序入口//// 3.虛擬機運行控制域//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));//// 4.VMEntry運行控制域//Vmx_VmWrite(VM_ENTRY_CONTROLS, VmxAdjustControls(0, MSR_IA32_VMX_ENTRY_CTLS));//// 5.VMExit運行控制域//Vmx_VmWrite(VM_EXIT_CONTROLS, VmxAdjustControls(0, MSR_IA32_VMX_EXIT_CTLS)); }NTSTATUS StartVirtualTechnology() {PVOID pVMXONRegion;PVOID pVMCSRegion;PVOID pStack;VMX_BASIC_MSR Msr;ULONG uRevId;_CR4 uCr4;_EFLAGS uEflags;if (!IsVTEnabled())return STATUS_NOT_SUPPORTED;//VMXE*((PULONG)&uCr4) = Asm_GetCr4();uCr4.VMXE = 1;Asm_SetCr4(*((PULONG)&uCr4));//VMX version*((PULONG)&Msr) = (ULONG)Asm_ReadMsr(MSR_IA32_VMX_BASIC);uRevId = Msr.RevId;//VMXON regionpVMXONRegion = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'vmon'); //4KBif (!pVMXONRegion){Log("ERROR:申請VMXON內(nèi)存區(qū)域失敗!", 0);return STATUS_MEMORY_NOT_ALLOCATED;}RtlZeroMemory(pVMXONRegion, 0x1000);g_VMXCPU.pVMXONRegion = pVMXONRegion;g_VMXCPU.pVMXONRegion_PA = MmGetPhysicalAddress(pVMXONRegion);*((PULONG)g_VMXCPU.pVMXONRegion) = uRevId;//VMXONVmx_VmxOn(g_VMXCPU.pVMXONRegion_PA.LowPart, g_VMXCPU.pVMXONRegion_PA.HighPart);// if CF = 0*((PULONG)&uEflags) = Asm_GetEflags();if (uEflags.CF != 0){Log("ERROR:開啟VT失敗!", 0);return STATUS_UNSUCCESSFUL;}Log("SUCCESS:開啟VT成功!", 0);//VMCSpVMCSRegion = ExAllocatePoolWithTag(NonPagedPool, 0x1000, 'vmon'); //4KBif (!pVMCSRegion){Log("ERROR:申請VMCS內(nèi)存區(qū)域失敗!", 0);return STATUS_MEMORY_NOT_ALLOCATED;}RtlZeroMemory(pVMCSRegion, 0x1000);*((PULONG)pVMCSRegion) = uRevId;g_VMXCPU.pVMCSRegion = pVMCSRegion;g_VMXCPU.pVMCSRegion_PA = MmGetPhysicalAddress(pVMCSRegion);Vmx_VmClear(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart);Vmx_VmPtrld(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart);//Stack,一半給Guest用,一半給Host用pStack = ExAllocatePoolWithTag(NonPagedPool, 0x2000, 'stck');if (!pStack){Log("ERROR:申請Stack內(nèi)存區(qū)域失敗!", 0);return STATUS_MEMORY_NOT_ALLOCATED;}RtlZeroMemory(pStack, 0x2000);g_VMXCPU.pStack = pStack;//SetupSetupVMCS(); //設(shè)置VMCS字段//LaunchVmx_VmLaunch();//===================================================//正常情況下,VMLAUNCH執(zhí)行后,CPU會進入虛擬機中//如果走到這里,說明執(zhí)行失敗//===================================================Log("ERROR:VmLaunch指令調(diào)用失敗!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", Vmx_VmRead(VM_INSTRUCTION_ERROR))return STATUS_SUCCESS; }extern ULONG g_vmcall_arg; extern ULONG g_stop_esp; extern ULONG g_stop_eip;NTSTATUS StopVirtualTechnology() {_CR4 uCr4;g_vmcall_arg = 'STOP';__asm {pushadpushfdmov g_stop_esp, espmov g_stop_eip, offset STOP}Vmx_VmCall();STOP:__asm {popfdpopad}*((PULONG)&uCr4) = Asm_GetCr4();uCr4.VMXE = 0;Asm_SetCr4(*((PULONG)&uCr4));ExFreePool(g_VMXCPU.pVMXONRegion);ExFreePool(g_VMXCPU.pVMCSRegion);ExFreePool(g_VMXCPU.pStack);Log("SUCCESS:關(guān)閉VT成功!", 0);return STATUS_SUCCESS; } //exithandler.h #ifndef EXITHANDLER_H #define EXITHANDLER_Hvoid VMMEntryPoint(void);#endif //exithandler.c #include "exithandler.h" #include "vtsystem.h" #include "vtasm.h"GUEST_REGS g_GuestRegs;void HandleCPUID() {//特殊處理,用于測試VT是否開啟,注意保證參數(shù)的獨立性。if (g_GuestRegs.eax == 'Mini'){g_GuestRegs.ebx = 0x88888888;g_GuestRegs.ecx = 0x11111111;g_GuestRegs.edx = 0x12345678;}//正常情況,替Guest模擬執(zhí)行CPUIDelse Asm_CPUID(g_GuestRegs.eax, &g_GuestRegs.eax, &g_GuestRegs.ebx, &g_GuestRegs.ecx, &g_GuestRegs.edx); }ULONG g_vmcall_arg; ULONG g_stop_esp, g_stop_eip;void HandleVmCall() {if (g_vmcall_arg == 'STOP'){Vmx_VmClear(g_VMXCPU.pVMCSRegion_PA.LowPart, g_VMXCPU.pVMCSRegion_PA.HighPart);Vmx_VmxOff();__asm {mov esp, g_stop_espjmp g_stop_eip}}else {__asm int 3} }void HandleCrAccess() {ULONG movcrControlRegister;ULONG movcrAccessType;ULONG movcrOperandType; //只是讀了,沒有使用,通常都是寄存器ULONG movcrGeneralPurposeRegister;ULONG movcrLMSWSourceData;ULONG ExitQualification;ExitQualification = Vmx_VmRead(EXIT_QUALIFICATION); //獲取具體信息movcrControlRegister = (ExitQualification & 0x0000000F); //控制寄存器下標movcrAccessType = ((ExitQualification & 0x00000030) >> 4); //讀/寫movcrOperandType = ((ExitQualification & 0x00000040) >> 6); //寄存器/內(nèi)存movcrGeneralPurposeRegister = ((ExitQualification & 0x00000F00) >> 8); //寄存器下標if (movcrControlRegister != 3) { // not for cr3__asm int 3}if (movcrAccessType == 0) { // CR3 <-- reg32Vmx_VmWrite(GUEST_CR3, *(PULONG)((ULONG)&g_GuestRegs + 4 * movcrGeneralPurposeRegister));}else { // reg32 <-- CR3*(PULONG)((ULONG)&g_GuestRegs + 4 * movcrGeneralPurposeRegister) = Vmx_VmRead(GUEST_CR3);} }static void VMMEntryPointEbd(void) {ULONG ExitReason;ULONG ExitInstructionLength;ULONG GuestResumeEIP;ExitReason = Vmx_VmRead(VM_EXIT_REASON);ExitInstructionLength = Vmx_VmRead(VM_EXIT_INSTRUCTION_LEN);g_GuestRegs.eflags = Vmx_VmRead(GUEST_RFLAGS);g_GuestRegs.esp = Vmx_VmRead(GUEST_RSP);g_GuestRegs.eip = Vmx_VmRead(GUEST_RIP);//Log("ExitReason", ExitReason);//Log("g_GuestRegs.eip", g_GuestRegs.eip);switch (ExitReason){case EXIT_REASON_CPUID:HandleCPUID();Log("EXIT_REASON_CPUID", 0);break;case EXIT_REASON_VMCALL:HandleVmCall();Log("EXIT_REASON_VMCALL", 0);break;case EXIT_REASON_CR_ACCESS:HandleCrAccess();//Log("EXIT_REASON_CR_ACCESS", 0);break;default:Log("not handled reason: %p", ExitReason);__asm int 3;break;}//Resume:GuestResumeEIP = g_GuestRegs.eip + ExitInstructionLength;Vmx_VmWrite(GUEST_RIP, GuestResumeEIP);Vmx_VmWrite(GUEST_RSP, g_GuestRegs.esp);Vmx_VmWrite(GUEST_RFLAGS, g_GuestRegs.eflags); }void __declspec(naked) VMMEntryPoint(void) {__asm{mov g_GuestRegs.eax, eaxmov g_GuestRegs.ecx, ecxmov g_GuestRegs.edx, edxmov g_GuestRegs.ebx, ebxmov g_GuestRegs.esp, espmov g_GuestRegs.ebp, ebpmov g_GuestRegs.esi, esimov g_GuestRegs.edi, edipushfdpop eaxmov g_GuestRegs.eflags, eax//需要設(shè)置fs和gs,否則無法正常運行mov ax, fsmov fs, axmov ax, gsmov gs, ax}//盡量不要在裸函數(shù)中定義局部變量,或?qū)崿F(xiàn)太多功能,最好封裝成函數(shù)VMMEntryPointEbd();__asm {mov eax, g_GuestRegs.eaxmov ecx, g_GuestRegs.ecxmov edx, g_GuestRegs.edxmov ebx, g_GuestRegs.ebxmov esp, g_GuestRegs.espmov ebp, g_GuestRegs.ebpmov esi, g_GuestRegs.esimov edi, g_GuestRegs.edi//vmresume__emit 0x0f__emit 0x01__emit 0xc3} } //driver.c #include <ntddk.h> #include "vtasm.h" #include "vtsystem.h"VOID DriverUnload(PDRIVER_OBJECT pDriver) {StopVirtualTechnology();DbgPrint("Driver unload. \r\n"); }ULONG g_back_esp; ULONG g_back_eip;NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path) {DbgPrint("Driver load. \r\n");pDriver->DriverUnload = DriverUnload;__asm{pushadpushfdmov g_back_esp, espmov g_back_eip, offset BACK}StartVirtualTechnology(); //開啟VTBACK:__asm{popfdpopad}//Log("Return To DriverEntry", 0);return STATUS_SUCCESS; }執(zhí)行結(jié)果:
參考資料
- VT虛擬化架構(gòu)編寫視頻教程①~⑥課
- 周鶴《VT技術(shù)入門》系列視頻教程
- github項目:VT_Learn
- github項目: HyperPlatform
- Intel開發(fā)手冊 卷3:Chapter 23 ~ Chapter 33
- x86內(nèi)部函數(shù)列表
總結(jié)
以上是生活随笔為你收集整理的Intel VT学习笔记(六)—— VM-Exit Handler的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Intel VT学习笔记(五)—— 调试
- 下一篇: Intel VT学习笔记(七)—— EP