Virtual Machine Monitor source
来源:互联网 发布:mac 看图软件 编辑:程序博客网 时间:2024/05/21 09:32
/* Virtual Machine Monitor Copyright (C) 2007 Shawn Embleton This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include <ntddk.h>#pragma warning(disable: 4133 4102)#define IA32_VMX_BASIC_MSR_CODE 0x480#define IA32_FEATURE_CONTROL_CODE 0x03AVOIDKeSetSystemAffinityThread ( IN KAFFINITY Affinity );//////////////////// //// PROTOTYPES //// ////////////////////NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath );VOID DriverUnload( IN PDRIVER_OBJECT DriverObject );VOID StartVMX( );VOID VMMEntryPoint( );typedef struct _VMX_FEATURES{ unsigned SSE3 :1; // SSE3 Extensions unsigned RES1 :2; unsigned MONITOR :1; // MONITOR/WAIT unsigned DS_CPL :1; // CPL qualified Debug Store unsigned VMX :1; // Virtual Machine Technology unsigned RES2 :1; unsigned EST :1; // Enhanced Intel?Speedstep Technology unsigned TM2 :1; // Thermal monitor 2 unsigned SSSE3 :1; // SSSE3 extensions unsigned CID :1; // L1 context ID unsigned RES3 :2; unsigned CX16 :1; // CMPXCHG16B unsigned xTPR :1; // Update control unsigned PDCM :1; // Performance/Debug capability MSR unsigned RES4 :2; unsigned DCA :1; unsigned RES5 :13; } VMX_FEATURES;//////////////// //// EFLAGS //// ////////////////typedef struct _EFLAGS{ unsigned Reserved1 :10; unsigned ID :1; // Identification flag unsigned VIP :1; // Virtual interrupt pending unsigned VIF :1; // Virtual interrupt flag unsigned AC :1; // Alignment check unsigned VM :1; // Virtual 8086 mode unsigned RF :1; // Resume flag unsigned Reserved2 :1; unsigned NT :1; // Nested task flag unsigned IOPL :2; // I/O privilege level unsigned OF :1; unsigned DF :1; unsigned IF :1; // Interrupt flag unsigned TF :1; // Task flag unsigned SF :1; // Sign flag unsigned ZF :1; // Zero flag unsigned Reserved3 :1; unsigned AF :1; // Borrow flag unsigned Reserved4 :1; unsigned PF :1; // Parity flag unsigned Reserved5 :1; unsigned CF :1; // Carry flag [Bit 0]} EFLAGS;///////////// //// MSR //// /////////////typedef struct _MSR{ ULONG Hi; ULONG Lo;} MSR;typedef struct _IA32_VMX_BASIC_MSR{ unsigned RevId :32; // Bits 31...0 contain the VMCS revision identifier unsigned szVmxOnRegion :12; // Bits 43...32 report # of bytes for VMXON region unsigned RegionClear :1; // Bit 44 set only if bits 32-43 are clear unsigned Reserved1 :3; // Undefined unsigned PhyAddrWidth :1; // Physical address width for referencing VMXON, VMCS, etc. unsigned DualMon :1; // Reports whether the processor supports dual-monitor // treatment of SMI and SMM unsigned MemType :4; // Memory type that the processor uses to access the VMCS unsigned VmExitReport :1; // Reports weather the procesor reports info in the VM-exit // instruction information field on VM exits due to execution // of the INS and OUTS instructions unsigned Reserved2 :9; // Undefined} IA32_VMX_BASIC_MSR;typedef struct _IA32_FEATURE_CONTROL_MSR{ unsigned Lock :1; // Bit 0 is the lock bit - cannot be modified once lock is set unsigned Reserved1 :1; // Undefined unsigned EnableVmxon :1; // Bit 2. If this bit is clear, VMXON causes a general protection exception unsigned Reserved2 :29; // Undefined unsigned Reserved3 :32; // Undefined} IA32_FEATURE_CONTROL_MSR;/////////////////// //// REGISTERS //// ///////////////////typedef struct _CR0_REG{ unsigned PE :1; // Protected Mode Enabled [Bit 0] unsigned MP :1; // Monitor Coprocessor FLAG unsigned EM :1; // Emulate FLAG unsigned TS :1; // Task Switched FLAG unsigned ET :1; // Extension Type FLAG unsigned NE :1; // Numeric Error unsigned Reserved1 :10; // unsigned WP :1; // Write Protect unsigned Reserved2 :1; // unsigned AM :1; // Alignment Mask unsigned Reserved3 :10; // unsigned NW :1; // Not Write-Through unsigned CD :1; // Cache Disable unsigned PG :1; // Paging Enabled} CR0_REG;typedef struct _CR4_REG{ unsigned VME :1; // Virtual Mode Extensions unsigned PVI :1; // Protected-Mode Virtual Interrupts unsigned TSD :1; // Time Stamp Disable unsigned DE :1; // Debugging Extensions unsigned PSE :1; // Page Size Extensions unsigned PAE :1; // Physical Address Extension unsigned MCE :1; // Machine-Check Enable unsigned PGE :1; // Page Global Enable unsigned PCE :1; // Performance-Monitoring Counter Enable unsigned OSFXSR :1; // OS Support for FXSAVE/FXRSTOR unsigned OSXMMEXCPT :1; // OS Support for Unmasked SIMD Floating-Point Exceptions unsigned Reserved1 :2; // unsigned VMXE :1; // Virtual Machine Extensions Enabled unsigned Reserved2 :18; // } CR4_REG;typedef struct _MISC_DATA{ unsigned Reserved1 :6; // [0-5] unsigned ActivityStates :3; // [6-8] unsigned Reserved2 :7; // [9-15] unsigned CR3Targets :9; // [16-24] // 512*(N+1) is the recommended maximum number of MSRs unsigned MaxMSRs :3; // [25-27] unsigned Reserved3 :4; // [28-31] unsigned MSEGRevID :32; // [32-63]} MISC_DATA;/////////////////// //// SELECTORS //// ///////////////////typedef struct _GDTR{ unsigned Limit :16; unsigned BaseLo :16; unsigned BaseHi :16;} GDTR;typedef struct _IDTR{ unsigned Limit :16; unsigned BaseLo :16; unsigned BaseHi :16;} IDTR;typedef struct _SEG_DESCRIPTOR{ unsigned LimitLo :16; unsigned BaseLo :16; unsigned BaseMid :8; unsigned Type :4; unsigned System :1; unsigned DPL :2; unsigned Present :1; unsigned LimitHi :4; unsigned AVL :1; unsigned L :1; unsigned DB :1; unsigned Gran :1; // Granularity unsigned BaseHi :8; } SEG_DESCRIPTOR;///////////// //// Log //// /////////////#define Log( message, value ) { DbgPrint("[vmm] %-40s [%08X]\n", message, value ); }///////////////// //// SET BIT //// /////////////////VOID SetBit( ULONG * dword, ULONG bit ){ ULONG mask = ( 1 << bit ); *dword = *dword | mask;}/////////////////// //// CLEAR BIT //// ///////////////////VOID ClearBit( ULONG * dword, ULONG bit ){ ULONG mask = 0xFFFFFFFF; ULONG sub = ( 1 << bit ); mask = mask - sub; *dword = *dword & mask;}///////////////// //// Globals //// /////////////////ULONG *pVMXONRegion = NULL; // Memory address of VMXON region.ULONG *pVMCSRegion = NULL;ULONG VMXONRegionSize = 0;ULONG VMCSRegionSize = 0;ULONG ErrorCode = 0;EFLAGS eFlags = {0};MSR msr = {0};PVOID FakeStack = NULL;ULONG HandlerLogging = 0;ULONG ScrubTheLaunch = 0;// Writes the contents of registers EDX:EAX into the 64-bit model specific// register (MSR) specified in the ECX register. The contents of the EDX// register are copied to high-order 32 bits of the selected MSR and the// contents of the EAX register are copied to low-order 32 bits of the MSR.//VOID WriteVMCS( ULONG encoding, ULONG value ){ __asm { PUSHAD PUSH value MOV EAX, encoding _emit 0x0F // VMWRITE EAX, [ESP] _emit 0x79 _emit 0x04 _emit 0x24 POP EAX POPAD }}// Loads the contents of a 64-bit model specific register (MSR) specified// in the ECX register into registers EDX:EAX. The EDX register is loaded// with the high-order 32 bits of the MSR and the EAX register is loaded// with the low-order 32 bits.// msr.Hi --> EDX// msr.Lo --> EAX//VOID ReadMSR( ULONG msrEncoding ){ __asm { PUSHAD MOV ECX, msrEncoding RDMSR MOV msr.Hi, EDX MOV msr.Lo, EAX POPAD }}// Write the msr data structure into MSR specified by msrEncoding.// msr.Hi <-- EDX// msr.Lo <-- EAX//VOID WriteMSR( ULONG msrEncoding ){ __asm { PUSHAD MOV EDX, msr.Hi MOV EAX, msr.Lo MOV ECX, msrEncoding WRMSR POPAD }}ULONG GetSegmentDescriptorBase( ULONG gdt_base , USHORT seg_selector ){ ULONG base = 0; SEG_DESCRIPTOR segDescriptor = {0}; RtlCopyBytes( &segDescriptor, (ULONG *)(gdt_base + (seg_selector >> 3) * 8), 8 ); base = segDescriptor.BaseHi; base <<= 8; base |= segDescriptor.BaseMid; base <<= 16; base |= segDescriptor.BaseLo; return base;}ULONG GetSegmentDescriptorDPL( ULONG gdt_base , USHORT seg_selector ){ SEG_DESCRIPTOR segDescriptor = {0}; RtlCopyBytes( &segDescriptor, (ULONG *)(gdt_base + (seg_selector >> 3) * 8), 8 ); return segDescriptor.DPL;}ULONG GetSegmentDescriptorLimit( ULONG gdt_base , USHORT seg_selector ){ SEG_DESCRIPTOR segDescriptor = {0}; RtlCopyBytes( &segDescriptor, (ULONG *)(gdt_base + (seg_selector >> 3) * 8), 8 ); //return segDescriptor.LimitLo; return ( (segDescriptor.LimitHi << 16) | segDescriptor.LimitLo );}PHYSICAL_ADDRESS PhysicalVMXONRegionPtr;PHYSICAL_ADDRESS PhysicalVMCSRegionPtr;VMX_FEATURES vmxFeatures;IA32_VMX_BASIC_MSR vmxBasicMsr ;IA32_FEATURE_CONTROL_MSR vmxFeatureControl ;CR0_REG cr0_reg = {0};CR4_REG cr4_reg = {0};ULONG temp32 = 0;USHORT temp16 = 0;GDTR gdt_reg = {0};IDTR idt_reg = {0};ULONG gdt_base = 0;ULONG idt_base = 0;USHORT mLDT = 0;USHORT seg_selector = 0;SEG_DESCRIPTOR segDescriptor = {0};MISC_DATA misc_data = {0};PVOID GuestReturn = NULL;ULONG GuestStack = 0;///////////// //// VMX //// /////////////__declspec( naked ) VOID StartVMX( ){ // // Get the Guest Return EIP. // // // Hi | | // +-----------+ // | EIP | // +-----------+ <-- ESP after the CALL // Lo | | // // __asm POP GuestReturn Log("Guest Return EIP" , GuestReturn ); /////////////////////////// // // // SET THREAD AFFINITY // // // /////////////////////////// Log( "Enabling VMX mode on CPU 0", 0 ); KeSetSystemAffinityThread( (KAFFINITY) 0x00000001 ); Log( "Running on Processor" , KeGetCurrentProcessorNumber() ); //////////////// // // // GDT Info // // // //////////////// __asm { SGDT gdt_reg } temp32 = 0; temp32 = gdt_reg.BaseHi; temp32 <<= 16; temp32 |= gdt_reg.BaseLo; gdt_base = temp32; Log( "GDT Base", gdt_base ); Log( "GDT Limit", gdt_reg.Limit ); //////////////////////////// // // // IDT Segment Selector // // // //////////////////////////// __asm SIDT idt_reg temp32 = 0; temp32 = idt_reg.BaseHi; temp32 <<= 16; temp32 |= idt_reg.BaseLo; idt_base = temp32; Log( "IDT Base", idt_base ); Log( "IDT Limit", idt_reg.Limit ); // (1) Check VMX support in processor using CPUID. __asm { PUSHAD MOV EAX, 1 CPUID // ECX contains the VMX_FEATURES FLAGS (VMX supported if bit 5 equals 1) MOV vmxFeatures, ECX MOV EAX, 0x80000008 CPUID MOV temp32, EAX POPAD } if( vmxFeatures.VMX == 0 ) { Log( "VMX Support Not Present." , vmxFeatures ); goto Abort; } Log( "VMX Support Present." , vmxFeatures ); // (2) Determine the VMX capabilities supported by the processor through // the VMX capability MSRs. __asm { PUSHAD MOV ECX, IA32_VMX_BASIC_MSR_CODE RDMSR LEA EBX, vmxBasicMsr MOV [EBX+4], EDX MOV [EBX], EAX MOV ECX, IA32_FEATURE_CONTROL_CODE RDMSR LEA EBX, vmxFeatureControl MOV [EBX+4], EDX MOV [EBX], EAX POPAD }; // (3) Create a VMXON region in non-pageable memory of a size specified by // IA32_VMX_BASIC_MSR and aligned to a 4-byte boundary. The VMXON region // must be hosted in cache-coherent memory. Log( "VMXON Region Size" , vmxBasicMsr.szVmxOnRegion ) ; Log( "VMXON Access Width Bit" , vmxBasicMsr.PhyAddrWidth ); Log( " [ 1] --> 32-bit" , 0 ); Log( " [ 0] --> 64-bit" , 0 ); Log( "VMXON Memory Type", vmxBasicMsr.MemType ); Log( " [ 0] --> Strong Uncacheable" , 0 ); Log( " [ 1-5] --> Unused" , 0 ); Log( " [ 6] --> Write Back" , 0 ); Log( " [7-15] --> Unused" , 0 ); VMXONRegionSize = vmxBasicMsr.szVmxOnRegion; switch( vmxBasicMsr.MemType ) { case 0: Log( "Unsupported memory type." , vmxBasicMsr.MemType ); goto Abort; break; case 6: break; default: Log( "ERROR : Unknown VMXON Region memory type." , 0); goto Abort; break; } // (4) Initialize the version identifier in the VMXON region (first 32 bits) // with the VMCS revision identifier reported by capability MSRs. *(pVMXONRegion) = vmxBasicMsr.RevId; Log( "vmxBasicMsr.RevId" , vmxBasicMsr.RevId ); // (5) Ensure the current processor operating mode meets the required CR0 // fixed bits (CR0.PE=1, CR0.PG=1). Other required CR0 fixed bits can // be detected through the IA32_VMX_CR0_FIXED0 and IA32_VMX_CR0_FIXED1 // MSRs. __asm { PUSH EAX MOV EAX, CR0 MOV cr0_reg, EAX POP EAX } if( cr0_reg.PE != 1 ) { Log( "ERROR : Protected Mode not enabled." , 0 ); Log( "Value of CR0" , cr0_reg ); goto Abort; } Log( "Protected Mode enabled." , 0 ); if( cr0_reg.PG != 1 ) { Log( "ERROR : Paging not enabled." , 0 ); Log( "Value of CR0" , cr0_reg ); goto Abort; } Log( "Paging enabled." , 0 ); cr0_reg.NE = 1; __asm { PUSH EAX MOV EAX, cr0_reg MOV CR0, EAX POP EAX } // (6) Enable VMX operation by setting CR4.VMXE=1 [bit 13]. Ensure the // resultant CR4 value supports all the CR4 fixed bits reported in // the IA32_VMX_CR4_FIXED0 and IA32_VMX_CR4_FIXED1 MSRs. __asm { PUSH EAX _emit 0x0F // MOV EAX, CR4 _emit 0x20 _emit 0xE0 MOV cr4_reg, EAX POP EAX } Log( "CR4" , cr4_reg ); cr4_reg.VMXE = 1; Log( "CR4" , cr4_reg ); __asm { PUSH EAX MOV EAX, cr4_reg _emit 0x0F // MOV CR4, EAX _emit 0x22 _emit 0xE0 POP EAX } // (7) Ensure that the IA32_FEATURE_CONTROL_MSR (MSR index 0x3A) has been // properly programmed and that its lock bit is set (bit 0=1). This MSR // is generally configured by the BIOS using WRMSR. Log( "IA32_FEATURE_CONTROL Lock Bit" , vmxFeatureControl.Lock ); if( vmxFeatureControl.Lock != 1 ) { Log( "ERROR : Feature Control Lock Bit != 1." , 0 ); goto Abort; } // (8) Execute VMXON with the physical address of the VMXON region as the // operand. Check successful execution of VMXON by checking if // RFLAGS.CF=0. __asm { PUSH DWORD PTR 0 PUSH DWORD PTR PhysicalVMXONRegionPtr.LowPart _emit 0xF3 // VMXON [ESP] _emit 0x0F _emit 0xC7 _emit 0x34 _emit 0x24 PUSHFD POP eFlags ADD ESP, 8 } if( eFlags.CF == 1 ) { Log( "ERROR : VMXON operation failed." , 0 ); goto Abort; } Log( "SUCCESS : VMXON operation completed." , 0 ); Log( "VMM is now running." , 0 ); // // *** The processor is now in VMX root operation! // // (1) Create a VMCS region in non-pageable memory of size specified by // the VMX capability MSR IA32_VMX_BASIC and aligned to 4-KBytes. // Software should read the capability MSRs to determine width of the // physical addresses that may be used for a VMCS region and ensure // the entire VMCS region can be addressed by addresses with that width. // The term "guest-VMCS address" refers to the physical address of the // new VMCS region for the following steps. VMCSRegionSize = vmxBasicMsr.szVmxOnRegion; switch( vmxBasicMsr.MemType ) { case 0: Log( "Unsupported memory type." , vmxBasicMsr.MemType ); goto Abort; break; case 6: break; default: Log( "ERROR : Unknown VMCS Region memory type." , 0 ); goto Abort; break; } // (2) Initialize the version identifier in the VMCS (first 32 bits) // with the VMCS revision identifier reported by the VMX // capability MSR IA32_VMX_BASIC. *(pVMCSRegion) = vmxBasicMsr.RevId; // (3) Execute the VMCLEAR instruction by supplying the guest-VMCS address. // This will initialize the new VMCS region in memory and set the launch // state of the VMCS to "clear". This action also invalidates the // working-VMCS pointer register to FFFFFFFF_FFFFFFFFH. Software should // verify successful execution of VMCLEAR by checking if RFLAGS.CF = 0 // and RFLAGS.ZF = 0. __asm { PUSH DWORD PTR 0 PUSH DWORD PTR PhysicalVMCSRegionPtr.LowPart _emit 0x66 // VMCLEAR [ESP] _emit 0x0F _emit 0xc7 _emit 0x34 _emit 0x24 ADD ESP, 8 PUSHFD POP eFlags } if( eFlags.CF != 0 || eFlags.ZF != 0 ) { Log( "ERROR : VMCLEAR operation failed." , 0 ); goto Abort; } Log( "SUCCESS : VMCLEAR operation completed." , 0 ); // (4) Execute the VMPTRLD instruction by supplying the guest-VMCS address. // This initializes the working-VMCS pointer with the new VMCS region’s // physical address. __asm { PUSH DWORD PTR 0 PUSH DWORD PTR PhysicalVMCSRegionPtr.LowPart _emit 0x0F // VMPTRLD [ESP] _emit 0xC7 _emit 0x34 _emit 0x24 ADD ESP, 8 } // // *************************************** // * * // * H.1.1 16-Bit Guest-State Fields * // * * // *************************************** // // Guest ES selector 00000800H __asm MOV seg_selector, ES Log( "Setting Guest ES Selector" , seg_selector ); WriteVMCS( 0x00000800, seg_selector ); // Guest CS selector 00000802H __asm MOV seg_selector, CS Log( "Setting Guest CS Selector" , seg_selector ); WriteVMCS( 0x00000802, seg_selector ); // Guest SS selector 00000804H __asm MOV seg_selector, SS Log( "Setting Guest SS Selector" , seg_selector ); WriteVMCS( 0x00000804, seg_selector ); // Guest DS selector 00000806H __asm MOV seg_selector, DS Log( "Setting Guest DS Selector" , seg_selector ); WriteVMCS( 0x00000806, seg_selector ); // Guest FS selector 00000808H __asm MOV seg_selector, FS Log( "Setting Guest FS Selector" , seg_selector ); WriteVMCS( 0x00000808, seg_selector ); // Guest GS selector 0000080AH __asm MOV seg_selector, GS Log( "Setting Guest GS Selector" , seg_selector ); WriteVMCS( 0x0000080A, seg_selector ); // Guest TR selector 0000080EH __asm STR seg_selector ClearBit( &seg_selector, 2 ); // TI Flag Log( "Setting Guest TR Selector" , seg_selector ); WriteVMCS( 0x0000080E, seg_selector ); // ************************************** // * * // * H.1.2 16-Bit Host-State Fields * // * * // ************************************** // // Host ES selector 00000C00H __asm MOV seg_selector, ES seg_selector &= 0xFFFC; Log( "Setting Host ES Selector" , seg_selector ); WriteVMCS( 0x00000C00, seg_selector ); // Host CS selector 00000C02H __asm MOV seg_selector, CS Log( "Setting Host CS Selector" , seg_selector ); WriteVMCS( 0x00000C02, seg_selector ); // Host SS selector 00000C04H __asm MOV seg_selector, SS Log( "Setting Host SS Selector" , seg_selector ); WriteVMCS( 0x00000C04, seg_selector ); // Host DS selector 00000C06H __asm MOV seg_selector, DS seg_selector &= 0xFFFC; Log( "Setting Host DS Selector" , seg_selector ); WriteVMCS( 0x00000C06, seg_selector ); // Host FS selector 00000C08H __asm MOV seg_selector, FS Log( "Setting Host FS Selector" , seg_selector ); WriteVMCS( 0x00000C08, seg_selector ); // Host GS selector 00000C0AH __asm MOV seg_selector, GS seg_selector &= 0xFFFC; Log( "Setting Host GS Selector" , seg_selector ); WriteVMCS( 0x00000C0A, seg_selector ); // Host TR selector 00000C0CH __asm STR seg_selector Log( "Setting Host TR Selector" , seg_selector ); WriteVMCS( 0x00000C0C, seg_selector ); // *************************************** // * * // * H.2.2 64-Bit Guest-State Fields * // * * // *************************************** // // VMCS Link Pointer (full) 00002800H temp32 = 0xFFFFFFFF; Log( "Setting VMCS Link Pointer (full)" , temp32 ); WriteVMCS( 0x00002800, temp32 ); // VMCS link pointer (high) 00002801H temp32 = 0xFFFFFFFF; Log( "Setting VMCS Link Pointer (high)" , temp32 ); WriteVMCS( 0x00002801, temp32 ); // Reserved Bits of IA32_DEBUGCTL MSR must be 0 // (1D9H) ReadMSR( 0x000001D9 ); Log( "IA32_DEBUGCTL MSR" , msr.Lo ); // Guest IA32_DEBUGCTL (full) 00002802H temp32 = msr.Lo; Log( "Setting Guest IA32_DEBUGCTL (full)" , temp32 ); WriteVMCS( 0x00002802, temp32 ); // Guest IA32_DEBUGCTL (high) 00002803H temp32 = msr.Hi; Log( "Setting Guest IA32_DEBUGCTL (high)" , temp32 ); WriteVMCS( 0x00002803, temp32 ); // *********************************** // * * // * H.3.1 32-Bit Control Fields * // * * // *********************************** // // Pin-based VM-execution controls 00004000H // IA32_VMX_PINBASED_CTLS MSR (index 481H) ReadMSR( 0x481 ); Log( "Pin-based allowed-0" , msr.Lo ); Log( "Pin-based allowed-1" , msr.Hi ); temp32 = 0; temp32 |= msr.Lo; temp32 &= msr.Hi; //SetBit( &temp32, 3 ); Log( "Setting Pin-Based Controls Mask" , temp32 ); WriteVMCS( 0x00004000, temp32 ); // Primary processor-based VM-execution controls 00004002H // IA32_VMX_PROCBASED_CTLS MSR (index 482H) ReadMSR( 0x482 ); Log( "Proc-based allowed-0" , msr.Lo ); Log( "Proc-based allowed-1" , msr.Hi ); temp32 = 0; temp32 |= msr.Lo; temp32 &= msr.Hi; Log( "Setting Pri Proc-Based Controls Mask" , temp32 ); WriteVMCS( 0x00004002, temp32 ); // Get the CR3-target count, MSR store/load counts, et cetera // // IA32_VMX_MISC MSR (index 485H) ReadMSR( 0x485 ); Log( "Misc Data" , msr.Lo ); //Log( "Misc Data" , msr.Hi ); RtlCopyBytes( &misc_data, &msr.Lo, 4 ); Log( " ActivityStates" , misc_data.ActivityStates ); Log( " CR3Targets" , misc_data.CR3Targets ); Log( " MaxMSRs" , misc_data.MaxMSRs ); // VM-exit controls 0000400CH // IA32_VMX_EXIT_CTLS MSR (index 483H) ReadMSR( 0x483 ); Log( "Exit controls allowed-0" , msr.Lo ); Log( "Exit controls allowed-1" , msr.Hi ); temp32 = 0; temp32 |= msr.Lo; temp32 &= msr.Hi; SetBit( &temp32, 15 ); // Acknowledge Interrupt On Exit Log( "Setting VM-Exit Controls Mask" , temp32 ); WriteVMCS( 0x0000400C, temp32 ); // VM-entry controls 00004012H // IA32_VMX_ENTRY_CTLS MSR (index 484H) ReadMSR( 0x484 ); Log( "VMX Entry allowed-0" , msr.Lo ); Log( "VMX Entry allowed-1" , msr.Hi ); temp32 = 0; temp32 |= msr.Lo; temp32 &= msr.Hi; ClearBit( &temp32 , 9 ); // IA-32e Mode Guest Disable Log( "Setting VM-Entry Controls Mask" , temp32 ); WriteVMCS( 0x00004012, temp32 ); // *************************************** // * * // * H.3.3 32-Bit Guest-State Fields * // * * // *************************************** // // Guest ES limit 00004800H __asm MOV seg_selector, ES temp32 = 0; temp32 = GetSegmentDescriptorLimit( gdt_base, seg_selector ); Log( "Setting Guest ES limit" , 0xFFFFFFFF ); WriteVMCS( 0x00004800, 0xFFFFFFFF ); // Guest CS limit 00004802H __asm MOV seg_selector, CS temp32 = 0; temp32 = GetSegmentDescriptorLimit( gdt_base, seg_selector ); Log( "Setting Guest CS limit" , 0xFFFFFFFF ); WriteVMCS( 0x00004802, 0xFFFFFFFF ); // Guest SS limit 00004804H __asm MOV seg_selector, SS temp32 = 0; temp32 = GetSegmentDescriptorLimit( gdt_base, seg_selector ); Log( "Setting Guest SS limit" , 0xFFFFFFFF ); WriteVMCS( 0x00004804, 0xFFFFFFFF ); // Guest DS limit 00004806H __asm MOV seg_selector, DS temp32 = 0; temp32 = GetSegmentDescriptorLimit( gdt_base, seg_selector ); Log( "Setting Guest DS limit" , 0xFFFFFFFF ); WriteVMCS( 0x00004806, 0xFFFFFFFF ); // Guest FS limit 00004808H __asm MOV seg_selector, FS temp32 = 0; temp32 = GetSegmentDescriptorLimit( gdt_base, seg_selector ); Log( "Setting Guest FS limit" , 0x00001000 ); WriteVMCS( 0x00004808, 0x00001000 ); // Guest GS limit 0000480AH __asm MOV seg_selector, GS temp32 = 0; temp32 = GetSegmentDescriptorLimit( gdt_base, seg_selector ); Log( "Setting Guest GS limit" , 0xFFFFFFFF ); WriteVMCS( 0x0000480A, 0xFFFFFFFF ); // Guest TR limit 0000480EH __asm { PUSH EAX STR AX MOV mLDT, AX POP EAX } temp32 = 0; temp32 = GetSegmentDescriptorLimit( gdt_base, mLDT ); Log( "Setting Guest TR limit" , temp32 ); WriteVMCS( 0x0000480E, temp32 ); // Guest GDTR limit 00004810H Log( "Setting Guest GDTR limit" , gdt_reg.Limit ); WriteVMCS( 0x00004810, gdt_reg.Limit ); // Guest IDTR limit 00004812H Log( "Setting Guest IDTR limit" , idt_reg.Limit ); WriteVMCS( 0x00004812, idt_reg.Limit ); __asm MOV seg_selector, CS temp32 = seg_selector; temp32 >>= 3; temp32 *= 8; temp32 += (gdt_base + 5); // CS Segment Descriptor __asm { PUSHAD MOV EAX, temp32 MOV EBX, [EAX] MOV temp32, EBX POPAD } temp32 &= 0x0000F0FF; Log( "Setting Guest CS access rights" , temp32 ); WriteVMCS( 0x00004816, temp32 ); __asm MOV seg_selector, DS temp32 = seg_selector; temp32 >>= 3; temp32 *= 8; temp32 += (gdt_base + 5); // DS Segment Descriptor __asm { PUSHAD MOV EAX, temp32 MOV EBX, [EAX] MOV temp32, EBX POPAD } temp32 &= 0x0000F0FF; Log( "Setting Guest DS access rights" , temp32 ); WriteVMCS( 0x0000481A, temp32 ); __asm MOV seg_selector, ES temp32 = seg_selector; temp32 >>= 3; temp32 *= 8; temp32 += (gdt_base + 5); // ES Segment Descriptor __asm { PUSHAD MOV EAX, temp32 MOV EBX, [EAX] MOV temp32, EBX POPAD } temp32 &= 0x0000F0FF; Log( "Setting Guest ES access rights" , temp32 ); WriteVMCS( 0x00004814, temp32 ); __asm MOV seg_selector, FS temp32 = seg_selector; temp32 >>= 3; temp32 *= 8; temp32 += (gdt_base + 5); // FS Segment Descriptor __asm { PUSHAD MOV EAX, temp32 MOV EBX, [EAX] MOV temp32, EBX POPAD } temp32 &= 0x0000F0FF; temp32 &= 0xFFFF7FFF; // Granularity Bit = 0 Log( "Setting Guest FS access rights" , temp32 ); WriteVMCS( 0x0000481C, temp32 ); __asm MOV seg_selector, GS temp32 = seg_selector; temp32 >>= 3; temp32 *= 8; temp32 += (gdt_base + 5); // GS Segment Descriptor __asm { PUSHAD MOV EAX, temp32 MOV EBX, [EAX] MOV temp32, EBX POPAD } temp32 &= 0x0000F0FF; SetBit( &temp32, 16 ); // Unusable Log( "Setting Guest GS access rights" , temp32 ); WriteVMCS( 0x0000481E, temp32 ); __asm MOV seg_selector, SS temp32 = seg_selector; temp32 >>= 3; temp32 *= 8; temp32 += (gdt_base + 5); // SS Segment Descriptor __asm { PUSHAD MOV EAX, temp32 MOV EBX, [EAX] MOV temp32, EBX POPAD } temp32 &= 0x0000F0FF; Log( "Setting Guest SS access rights" , temp32 ); WriteVMCS( 0x00004818, temp32 ); __asm STR seg_selector temp32 = seg_selector; temp32 >>= 3; temp32 *= 8; temp32 += (gdt_base + 5); // TR Segment Descriptor __asm { PUSHAD MOV EAX, temp32 MOV EBX, [EAX] MOV temp32, EBX POPAD } temp32 &= 0x0000F0FF; Log( "Setting Guest TR access rights" , temp32 ); WriteVMCS( 0x00004822, temp32 ); // Guest LDTR access rights 00004820H temp32 = 0; SetBit( &temp32, 16 ); // Unusable Log( "Setting Guest LDTR access rights" , temp32 ); WriteVMCS( 0x00004820, temp32 ); // Guest IA32_SYSENTER_CS 0000482AH // (174H) ReadMSR( 0x174 ); Log( "Setting Guest IA32_SYSENTER_CS" , (ULONG)msr.Lo ); WriteVMCS( 0x0000482A, msr.Lo ); // ************************************** // * * // * H.3.4 32-Bit Host-State Fields * // * * // ************************************** // // Host IA32_SYSENTER_CS 00004C00H // (174H) ReadMSR( 0x174 ); Log( "Setting Host IA32_SYSENTER_CS" , (ULONG)msr.Lo ); WriteVMCS( 0x00004C00, msr.Lo ); // ********************************************** // * * // * H.4.3 Natural-Width Guest-State Fields * // * * // ********************************************** // // Guest CR0 00006800H __asm { PUSH EAX MOV EAX, CR0 MOV temp32, EAX POP EAX } ReadMSR( 0x486 ); // IA32_VMX_CR0_FIXED0 Log( "IA32_VMX_CR0_FIXED0" , msr.Lo ); ReadMSR( 0x487 ); // IA32_VMX_CR0_FIXED1 Log( "IA32_VMX_CR0_FIXED1" , msr.Lo ); SetBit( &temp32, 0 ); // PE SetBit( &temp32, 5 ); // NE SetBit( &temp32, 31 ); // PG Log( "Setting Guest CR0" , temp32 ); WriteVMCS( 0x00006800, temp32 ); // Guest CR3 00006802H __asm { PUSH EAX _emit 0x0F // MOV EAX, CR3 _emit 0x20 _emit 0xD8 MOV temp32, EAX POP EAX } Log( "Setting Guest CR3" , temp32 ); WriteVMCS( 0x00006802, temp32 ); // Guest CR4 00006804H __asm { PUSH EAX _emit 0x0F // MOV EAX, CR4 _emit 0x20 _emit 0xE0 MOV temp32, EAX POP EAX } ReadMSR( 0x488 ); // IA32_VMX_CR4_FIXED0 Log( "IA32_VMX_CR4_FIXED0" , msr.Lo ); ReadMSR( 0x489 ); // IA32_VMX_CR4_FIXED1 Log( "IA32_VMX_CR4_FIXED1" , msr.Lo ); SetBit( &temp32, 13 ); // VMXE Log( "Setting Guest CR4" , temp32 ); WriteVMCS( 0x00006804, temp32 ); // Guest ES base 00006806H __asm MOV seg_selector, ES temp32 = 0; temp32 = GetSegmentDescriptorBase( gdt_base , seg_selector ); Log( "Setting Guest ES Base" , temp32 ); WriteVMCS( 0x00006806, temp32 ); // Guest CS base 00006808H __asm MOV seg_selector, CS temp32 = 0; temp32 = GetSegmentDescriptorBase( gdt_base , seg_selector ); Log( "Setting Guest CS Base" , temp32 ); WriteVMCS( 0x00006808, temp32 ); // Guest SS base 0000680AH __asm MOV seg_selector, SS temp32 = 0; temp32 = GetSegmentDescriptorBase( gdt_base , seg_selector ); Log( "Setting Guest SS Base" , temp32 ); WriteVMCS( 0x0000680A, temp32 ); // Guest DS base 0000680CH __asm MOV seg_selector, DS temp32 = 0; temp32 = GetSegmentDescriptorBase( gdt_base , seg_selector ); Log( "Setting Guest DS Base" , temp32 ); WriteVMCS( 0x0000680C, temp32 ); // Guest FS base 0000680EH __asm MOV seg_selector, FS temp32 = 0; temp32 = GetSegmentDescriptorBase( gdt_base , seg_selector ); Log( "Setting Guest FS Base" , temp32 ); WriteVMCS( 0x0000680E, temp32 ); // Guest TR base 00006814H __asm { PUSH EAX STR AX MOV mLDT, AX POP EAX } temp32 = 0; temp32 = GetSegmentDescriptorBase( gdt_base , mLDT ); Log( "Setting Guest TR Base" , temp32 ); WriteVMCS( 0x00006814, temp32 ); // Guest GDTR base 00006816H __asm { SGDT gdt_reg } temp32 = 0; temp32 = gdt_reg.BaseHi; temp32 <<= 16; temp32 |= gdt_reg.BaseLo; Log( "Setting Guest GDTR Base" , temp32 ); WriteVMCS( 0x00006816, temp32 ); // Guest IDTR base 00006818H __asm { SIDT idt_reg } temp32 = 0; temp32 = idt_reg.BaseHi; temp32 <<= 16; temp32 |= idt_reg.BaseLo; Log( "Setting Guest IDTR Base" , temp32 ); WriteVMCS( 0x00006818, temp32 ); // Guest RFLAGS 00006820H __asm { PUSHAD PUSHFD MOV EAX, 0x00006820 // VMWRITE EAX, [ESP] _emit 0x0F _emit 0x79 _emit 0x04 _emit 0x24 POP eFlags POPAD } Log( "Guest EFLAGS" , eFlags ); // Guest IA32_SYSENTER_ESP 00006824H // MSR (175H) ReadMSR( 0x175 ); Log( "Setting Guest IA32_SYSENTER_ESP" , msr.Lo ); WriteVMCS( 0x00006824, msr.Lo ); // Guest IA32_SYSENTER_EIP 00006826H // MSR (176H) ReadMSR( 0x176 ); Log( "Setting Guest IA32_SYSENTER_EIP" , msr.Lo ); WriteVMCS( 0x00006826, msr.Lo ); // ********************************************* // * * // * H.4.4 Natural-Width Host-State Fields * // * * // ********************************************* // // Host CR0 00006C00H __asm { PUSH EAX MOV EAX, CR0 MOV temp32, EAX POP EAX } SetBit( &temp32, 5 ); // Set NE Bit Log( "Setting Host CR0" , temp32 ); WriteVMCS( 0x00006C00, temp32 ); // Host CR3 00006C02H __asm { PUSH EAX _emit 0x0F // MOV EAX, CR3 _emit 0x20 _emit 0xD8 MOV temp32, EAX POP EAX } Log( "Setting Host CR3" , temp32 ); WriteVMCS( 0x00006C02, temp32 ); // Host CR4 00006C04H __asm { PUSH EAX _emit 0x0F // MOV EAX, CR4 _emit 0x20 _emit 0xE0 MOV temp32, EAX POP EAX } Log( "Setting Host CR4" , temp32 ); WriteVMCS( 0x00006C04, temp32 ); // Host FS base 00006C06H __asm MOV seg_selector, FS temp32 = 0; temp32 = GetSegmentDescriptorBase( gdt_base , seg_selector ); Log( "Setting Host FS Base" , temp32 ); WriteVMCS( 0x00006C06, temp32 ); // Host TR base 00006C0AH __asm { PUSH EAX STR AX MOV mLDT, AX POP EAX } temp32 = 0; temp32 = GetSegmentDescriptorBase( gdt_base , mLDT ); Log( "Setting Host TR Base" , temp32 ); WriteVMCS( 0x00006C0A, temp32 ); // Host GDTR base 00006C0CH __asm { SGDT gdt_reg } temp32 = 0; temp32 = gdt_reg.BaseHi; temp32 <<= 16; temp32 |= gdt_reg.BaseLo; Log( "Setting Host GDTR Base" , temp32 ); WriteVMCS( 0x00006C0C, temp32 ); // Host IDTR base 00006C0EH __asm { SIDT idt_reg } temp32 = 0; temp32 = idt_reg.BaseHi; temp32 <<= 16; temp32 |= idt_reg.BaseLo; Log( "Setting Host IDTR Base" , temp32 ); WriteVMCS( 0x00006C0E, temp32 ); // Host IA32_SYSENTER_ESP 00006C10H // MSR (175H) ReadMSR( 0x175 ); Log( "Setting Host IA32_SYSENTER_ESP" , msr.Lo ); WriteVMCS( 0x00006C10, msr.Lo ); // Host IA32_SYSENTER_EIP 00006C12H // MSR (176H) ReadMSR( 0x176 ); Log( "Setting Host IA32_SYSENTER_EIP" , msr.Lo ); WriteVMCS( 0x00006C12, msr.Lo ); // (5) Issue a sequence of VMWRITEs to initialize various host-state area // fields in the working VMCS. The initialization sets up the context // and entry-points to the VMM VIRTUAL-MACHINE MONITOR PROGRAMMING // CONSIDERATIONS upon subsequent VM exits from the guest. Host-state // fields include control registers (CR0, CR3 and CR4), selector fields // for the segment registers (CS, SS, DS, ES, FS, GS and TR), and base- // address fields (for FS, GS, TR, GDTR and IDTR; RSP, RIP and the MSRs // that control fast system calls). // // (6) Use VMWRITEs to set up the various VM-exit control fields, VM-entry // control fields, and VM-execution control fields in the VMCS. Care // should be taken to make sure the settings of individual fields match // the allowed 0 and 1 settings for the respective controls as reported // by the VMX capability MSRs (see Appendix G). Any settings inconsistent // with the settings reported by the capability MSRs will cause VM // entries to fail. // (7) Use VMWRITE to initialize various guest-state area fields in the // working VMCS. This sets up the context and entry-point for guest // execution upon VM entry. Chapter 22 describes the guest-state loading // and checking done by the processor for VM entries to protected and // virtual-8086 guest execution. // // Clear the VMX Abort Error Code prior to VMLAUNCH // RtlZeroMemory( (pVMCSRegion + 4), 4 ); Log( "Clearing VMX Abort Error Code" , *(pVMCSRegion + 4) ); // Set EIP, ESP for the Guest right before calling VMLAUNCH // Log( "Setting Guest ESP" , GuestStack ); WriteVMCS( 0x0000681C, (ULONG)GuestStack ); Log( "Setting Guest EIP" , GuestReturn ); WriteVMCS( 0x0000681E, (ULONG)GuestReturn ); /* // Allocate some stack space for the VMEntry and VMMHandler. // HighestAcceptableAddress.QuadPart = 0xFFFFFFFF; FakeStack = MmAllocateContiguousMemory( 0x2000, HighestAcceptableAddress ); Log( "FakeStack" , FakeStack ); */ // Set EIP, ESP for the Host right before calling VMLAUNCH // Log( "Setting Host ESP" , ((ULONG)FakeStack + 0x1FFF) ); WriteVMCS( 0x00006C14, ((ULONG)FakeStack + 0x1FFF) ); Log( "Setting Host EIP" , VMMEntryPoint ); WriteVMCS( 0x00006C16, (ULONG)VMMEntryPoint ); //////////////// // // // VMLAUNCH // // // //////////////// __asm { _emit 0x0F // VMLAUNCH _emit 0x01 _emit 0xC2 } __asm { PUSHFD POP eFlags } Log( "VMLAUNCH Failure" , 0xDEADF00D ) if( eFlags.CF != 0 || eFlags.ZF != 0 || TRUE ) { // // Get the ERROR number using VMCS field 00004400H // __asm { PUSHAD MOV EAX, 0x00004400 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV ErrorCode, EBX POPAD } Log( "VM Instruction Error" , ErrorCode ); }Abort: ScrubTheLaunch = 1; __asm { MOV ESP, GuestStack JMP GuestReturn }}////////////////////// //// DriverUnload //// //////////////////////VOID DriverUnload( IN PDRIVER_OBJECT DriverObject ){ ULONG ExitEFlags = 0; ULONG ExitEAX = 0; ULONG ExitECX = 0; ULONG ExitEDX = 0; ULONG ExitEBX = 0; ULONG ExitESP = 0; ULONG ExitEBP = 0; ULONG ExitESI = 0; ULONG ExitEDI = 0; DbgPrint( "[vmm-unload] Active Processor Bitmap [%08X]\n", (ULONG)KeQueryActiveProcessors( ) ); DbgPrint( "[vmm-unload] Disabling VMX mode on CPU 0.\n" ); KeSetSystemAffinityThread( (KAFFINITY) 0x00000001 ); __asm { PUSHAD MOV EAX, 0x12345678 _emit 0x0F // VMCALL _emit 0x01 _emit 0xC1 POPAD } DbgPrint( "[vmm-unload] Freeing memory regions.\n" ); MmFreeNonCachedMemory( pVMXONRegion , 4096 ); MmFreeNonCachedMemory( pVMCSRegion , 4096 ); ExFreePoolWithTag( FakeStack, 'HmmV' ); DbgPrint( "[vmm-unload] Driver Unloaded.\n");}////////////////////// //// Driver Entry //// //////////////////////NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ){ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; ULONG EntryEFlags = 0; ULONG cr4 = 0; ULONG EntryEAX = 0; ULONG EntryECX = 0; ULONG EntryEDX = 0; ULONG EntryEBX = 0; ULONG EntryESP = 0; ULONG EntryEBP = 0; ULONG EntryESI = 0; ULONG EntryEDI = 0; DriverObject->DriverUnload = DriverUnload; Log( "Driver Routines" , 0 ); Log( "---------------" , 0 ); Log( " Driver Entry", DriverEntry ); Log( " Driver Unload", DriverUnload ); Log( " StartVMX", StartVMX ); Log( " VMMEntryPoint", VMMEntryPoint ); // Check if PAE is enabled. // __asm { PUSH EAX _emit 0x0F // MOV EAX, CR4 _emit 0x20 _emit 0xE0 MOV cr4, EAX POP EAX } /*if( cr4 & 0x00000020 ) { Log( "******************************" , 0 ); Log( "Error : PAE must be disabled." , 0 ); Log( "Add the following to boot.ini:" , 0 ); Log( " /noexecute=alwaysoff /nopae" , 0 ); Log( "******************************" , 0 ); return STATUS_UNSUCCESSFUL; }*/ // Allocate the VMXON region memory. // pVMXONRegion = MmAllocateNonCachedMemory( 4096 ); if( pVMXONRegion == NULL ) { Log( "ERROR : Allocating VMXON Region memory." , 0 ); return STATUS_UNSUCCESSFUL; } Log( "VMXONRegion virtual address" , pVMXONRegion ); RtlZeroMemory( pVMXONRegion, 4096 ); PhysicalVMXONRegionPtr = MmGetPhysicalAddress( pVMXONRegion ); Log( "VMXONRegion physical address" , PhysicalVMXONRegionPtr.LowPart ); // Allocate the VMCS region memory. // pVMCSRegion = MmAllocateNonCachedMemory( 4096 ); if( pVMCSRegion == NULL ) { Log( "ERROR : Allocating VMCS Region memory." , 0 ); MmFreeNonCachedMemory( pVMXONRegion , 4096 ); return STATUS_UNSUCCESSFUL; } Log( "VMCSRegion virtual address" , pVMCSRegion ); RtlZeroMemory( pVMCSRegion, 4096 ); PhysicalVMCSRegionPtr = MmGetPhysicalAddress( pVMCSRegion ); Log( "VMCSRegion physical address" , PhysicalVMCSRegionPtr.LowPart ); // Allocate stack for the VM Exit Handler. // FakeStack = ExAllocatePoolWithTag( NonPagedPool , 0x2000, 'HmmV' ); if( FakeStack == NULL ) { Log( "ERROR : Allocating VM Exit Handler stack memory." , 0 ); MmFreeNonCachedMemory( pVMXONRegion , 4096 ); MmFreeNonCachedMemory( pVMCSRegion , 4096 ); return STATUS_UNSUCCESSFUL; } Log( "FakeStack" , FakeStack ); __asm { CLI MOV GuestStack, ESP } // Save the state of the architecture. // __asm { PUSHAD POP EntryEDI POP EntryESI POP EntryEBP POP EntryESP POP EntryEBX POP EntryEDX POP EntryECX POP EntryEAX PUSHFD POP EntryEFlags } StartVMX( ); // Restore the state of the architecture. // __asm { PUSH EntryEFlags POPFD PUSH EntryEAX PUSH EntryECX PUSH EntryEDX PUSH EntryEBX PUSH EntryESP PUSH EntryEBP PUSH EntryESI PUSH EntryEDI POPAD } __asm { STI MOV ESP, GuestStack } Log( "Running on Processor" , KeGetCurrentProcessorNumber() ); if( ScrubTheLaunch == 1 ) { Log( "ERROR : Launch aborted." , 0 ); MmFreeNonCachedMemory( pVMXONRegion , 4096 ); MmFreeNonCachedMemory( pVMCSRegion , 4096 ); ExFreePoolWithTag( FakeStack, 'HmmV' ); return STATUS_UNSUCCESSFUL; } Log( "VM is now executing." , 0 ); return STATUS_SUCCESS;}ULONG ExitReason;ULONG ExitQualification;ULONG ExitInterruptionInformation;ULONG ExitInterruptionErrorCode;ULONG IDTVectoringInformationField;ULONG IDTVectoringErrorCode;ULONG ExitInstructionLength;ULONG ExitInstructionInformation;ULONG GuestEIP;ULONG GuestResumeEIP;ULONG GuestESP;ULONG GuestCS;ULONG GuestCR0;ULONG GuestCR3;ULONG GuestCR4;ULONG GuestEFLAGS;ULONG GuestEAX;ULONG GuestEBX;ULONG GuestECX;ULONG GuestEDX;ULONG GuestEDI;ULONG GuestESI;ULONG GuestEBP;ULONG movcrControlRegister;ULONG movcrAccessType;ULONG movcrOperandType;ULONG movcrGeneralPurposeRegister;ULONG movcrLMSWSourceData;ULONG ErrorCode;///////////////////////// //// VMM Entry Point //// /////////////////////////__declspec( naked ) VOID VMMEntryPoint( ){ __asm CLI __asm PUSHAD // // Record the General-Purpose registers. // __asm MOV GuestEAX, EAX __asm MOV GuestEBX, EBX __asm MOV GuestECX, ECX __asm MOV GuestEDX, EDX __asm MOV GuestEDI, EDI __asm MOV GuestESI, ESI __asm MOV GuestEBP, EBP /////////////////// // // // Exit Reason // 0x00004400 // // /////////////////// __asm { PUSHAD MOV EAX, 0x00004402 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV ExitReason, EBX POPAD } if( ExitReason == 0x0000000A || // CPUID ExitReason == 0x00000012 || // VMCALL ExitReason == 0x0000001C || // MOV CR ExitReason == 0x0000001F || // RDMSR ExitReason == 0x00000020 || // WRMSR ( ExitReason > 0x00000012 && ExitReason < 0x0000001C ) ) { HandlerLogging = 0; } else { HandlerLogging = 1; } if( HandlerLogging ) { Log( "----- VMM Handler CPU0 -----", 0 ); Log( "Guest EAX" , GuestEAX ); Log( "Guest EBX" , GuestEBX ); Log( "Guest ECX" , GuestECX ); Log( "Guest EDX" , GuestEDX ); Log( "Guest EDI" , GuestEDI ); Log( "Guest ESI" , GuestESI ); Log( "Guest EBP" , GuestEBP ); Log( "Exit Reason" , ExitReason ); } ////////////////////////// // // // Exit Qualification // 00006400H // // ////////////////////////// __asm { PUSHAD MOV EAX, 0x00006400 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV ExitQualification, EBX POPAD } if( HandlerLogging ) Log( "Exit Qualification" , ExitQualification ); //////////////////////////////////////// // // // VM-Exit Interruption Information // 00004404H // // //////////////////////////////////////// __asm { PUSHAD MOV EAX, 0x00004404 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV ExitInterruptionInformation, EBX POPAD } if( HandlerLogging ) Log( "Exit Interruption Information" , ExitInterruptionInformation ); /////////////////////////////////////// // // // VM-Exit Interruption Error Code // 00004406H // // /////////////////////////////////////// __asm { PUSHAD MOV EAX, 0x00004406 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV ExitInterruptionErrorCode, EBX POPAD } if( HandlerLogging ) Log( "Exit Interruption Error Code" , ExitInterruptionErrorCode ); /////////////////////////////////////// // // // IDT-Vectoring Information Field // 00004408H // // /////////////////////////////////////// __asm { PUSHAD MOV EAX, 0x00004408 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV IDTVectoringInformationField, EBX POPAD } if( HandlerLogging ) Log( "IDT-Vectoring Information Field" , IDTVectoringInformationField ); //////////////////////////////// // // // IDT-Vectoring Error Code // 0000440AH // // //////////////////////////////// __asm { PUSHAD MOV EAX, 0x0000440A _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV IDTVectoringErrorCode, EBX POPAD } if( HandlerLogging ) Log( "IDT-Vectoring Error Code" , IDTVectoringErrorCode ); ////////////////////////////////// // // // VM-Exit Instruction Length // 0000440CH // // ////////////////////////////////// __asm { PUSHAD MOV EAX, 0x0000440C _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV ExitInstructionLength, EBX POPAD } if( HandlerLogging ) Log( "VM-Exit Instruction Length" , ExitInstructionLength ); /////////////////////////////////////// // // // VM-Exit Instruction Information // 0000440EH // // /////////////////////////////////////// __asm { PUSHAD MOV EAX, 0x0000440E _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV ExitInstructionInformation, EBX POPAD } if( HandlerLogging ) Log( "VM-Exit Instruction Information" , ExitInstructionInformation ); ///////////////// // // // Guest EIP // // // ///////////////// __asm { PUSHAD MOV EAX, 0x0000681E _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV GuestEIP, EBX POPAD } if( HandlerLogging ) Log( "VM Exit EIP" , GuestEIP ); // // Writing the Guest VMCS EIP uses general registers. // Must complete this before setting general registers // for guest return state. // GuestResumeEIP = GuestEIP + ExitInstructionLength; WriteVMCS( 0x0000681E, (ULONG)GuestResumeEIP ); ///////////////// // // // Guest ESP // // // ///////////////// __asm { PUSHAD MOV EAX, 0x0000681C _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV GuestESP, EBX POPAD } if( HandlerLogging ) Log( "VM Exit ESP" , GuestESP ); //////////////// // // // Guest CS // // // //////////////// __asm { PUSHAD MOV EAX, 0x00000802 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV GuestCS, EBX POPAD } if( HandlerLogging ) Log( "VM Exit CS" , GuestCS ); ///////////////// // // // Guest CR0 // // // ///////////////// __asm { PUSHAD MOV EAX, 0x00006800 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV GuestCR0, EBX POPAD } if( HandlerLogging ) Log( "VM Exit CR0" , GuestCR0 ); ///////////////// // // // Guest CR3 // // // ///////////////// __asm { PUSHAD MOV EAX, 0x00006802 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV GuestCR3, EBX POPAD } if( HandlerLogging ) Log( "VM Exit CR3" , GuestCR3 ); ///////////////// // // // Guest CR4 // // // ///////////////// __asm { PUSHAD MOV EAX, 0x00006804 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV GuestCR4, EBX POPAD } if( HandlerLogging ) Log( "VM Exit CR4" , GuestCR4 ); //////////////////// // // // Guest EFLAGS // // // //////////////////// __asm { PUSHAD MOV EAX, 0x00006820 _emit 0x0F // VMREAD EBX, EAX _emit 0x78 _emit 0xC3 MOV GuestEFLAGS, EBX POPAD } if( HandlerLogging ) Log( "VM Exit EFLAGS" , GuestEFLAGS ); ///////////////////////////////////////////// // // // *** EXIT REASON CHECKS START HERE *** // // // ///////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // // // VMCLEAR, VMLAUNCH, VMPTRLD, VMPTRST, VMREAD, VMWRITE, VMRESUME, VMXOFF, VMXON // // // ///////////////////////////////////////////////////////////////////////////////////// if( ExitReason > 0x00000012 && ExitReason < 0x0000001C ) { Log( "Request has been denied - CPU0", ExitReason ); __asm { POPAD JMP Resume } } ////////////// // // // VMCALL // // // ////////////// if( ExitReason == 0x00000012 ) { Log( "VMCALL detected - CPU0" , 0 ); if( GuestEAX == 0x12345678 ) { // Switch off VMX mode. // Log( "- Terminating VMX Mode.", 0xDEADDEAD ); __asm { _emit 0x0F // VMXOFF _emit 0x01 _emit 0xC4 } Log( "- Flow Control Return to Address" , GuestResumeEIP ); __asm { POPAD MOV ESP, GuestESP STI JMP GuestResumeEIP } } Log( "- Request has been denied." , ExitReason ); __asm { POPAD JMP Resume } } //////////// // // // INVD // // // //////////// if( ExitReason == 0x0000000C ) { Log( "INVD detected - CPU0" , 0 ); __asm { _emit 0x0F _emit 0x08 POPAD JMP Resume } } ///////////// // // // RDMSR // // // ///////////// if( ExitReason == 0x0000001F ) { Log( "Read MSR - CPU0" , GuestECX ); __asm { POPAD MOV ECX, GuestECX _emit 0x0F _emit 0x32 JMP Resume } } ///////////// // // // WRMSR // // // ///////////// if( ExitReason == 0x00000020 ) { Log( "Write MSR - CPU0" , GuestECX ); __asm { POPAD MOV ECX, GuestECX MOV EAX, GuestEAX MOV EDX, GuestEDX _emit 0x0F _emit 0x30 JMP Resume } } ///////////// // // // CPUID // // // ///////////// if( ExitReason == 0x0000000A ) { if( HandlerLogging ) { Log( "CPUID detected - CPU0", 0 ); Log( "- EAX", GuestEAX ); } if( GuestEAX == 0x00000000 ) { __asm { POPAD MOV EAX, 0x00000000 CPUID MOV EBX, 0x61656C43 MOV ECX, 0x2E636E6C MOV EDX, 0x74614872 JMP Resume } } __asm { POPAD MOV EAX, GuestEAX CPUID JMP Resume } } /////////////////////////////// // // // Control Register Access // // // /////////////////////////////// if( ExitReason == 0x0000001C ) { if( HandlerLogging ) Log( "Control Register Access detected.", 0 ); movcrControlRegister = ( ExitQualification & 0x0000000F ); movcrAccessType = ( ( ExitQualification & 0x00000030 ) >> 4 ); movcrOperandType = ( ( ExitQualification & 0x00000040 ) >> 6 ); movcrGeneralPurposeRegister = ( ( ExitQualification & 0x00000F00 ) >> 8 ); if( HandlerLogging ) { Log( "- movcrControlRegister", movcrControlRegister ); Log( "- movcrAccessType", movcrAccessType ); Log( "- movcrOperandType", movcrOperandType ); Log( "- movcrGeneralPurposeRegister", movcrGeneralPurposeRegister ); } // Control Register Access (CR3 <-- reg32) // if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 0 ) { WriteVMCS( 0x00006802, GuestEAX ); __asm POPAD goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 1 ) { WriteVMCS( 0x00006802, GuestECX ); __asm POPAD goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 2 ) { WriteVMCS( 0x00006802, GuestEDX ); __asm POPAD goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 3 ) { WriteVMCS( 0x00006802, GuestEBX ); __asm POPAD goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 4 ) { WriteVMCS( 0x00006802, GuestESP ); __asm POPAD goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 5 ) { WriteVMCS( 0x00006802, GuestEBP ); __asm POPAD goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 6 ) { WriteVMCS( 0x00006802, GuestESI ); __asm POPAD goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 7 ) { WriteVMCS( 0x00006802, GuestEDI ); __asm POPAD goto Resume; } // Control Register Access (reg32 <-- CR3) // if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 0 ) { __asm POPAD __asm MOV EAX, GuestCR3 goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 1 ) { __asm POPAD __asm MOV ECX, GuestCR3 goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 2 ) { __asm POPAD __asm MOV EDX, GuestCR3 goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 3 ) { __asm POPAD __asm MOV EBX, GuestCR3 goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 4 ) { __asm POPAD __asm MOV ESP, GuestCR3 goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 5 ) { __asm POPAD __asm MOV EBP, GuestCR3 goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 6 ) { __asm POPAD __asm MOV ESI, GuestCR3 goto Resume; } if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 7 ) { __asm POPAD __asm MOV EDI, GuestCR3 goto Resume; } } Exit: // // Switch off VMX mode. // Log( "Terminating VMX Mode.", 0xDEADDEAD ); __asm { _emit 0x0F // VMXOFF _emit 0x01 _emit 0xC4 } Log( "Flow Control Return to Address" , GuestEIP ); __asm { POPAD MOV ESP, GuestESP STI JMP GuestEIP } Resume: // Need to execute the VMRESUME without having changed // the state of the GPR and ESP et cetera. // __asm { STI _emit 0x0F // VMRESUME _emit 0x01 _emit 0xC3 }}
0 0
- Virtual Machine Monitor source
- Open Source Virtual Machine Software
- Linux KVM: Kernel Virtual Machine Monitor
- Hooking CPUID – A Virtual Machine Monitor Rootkit Framework
- kvm:linux的虚拟机监控器(kvm: the Linux Virtual Machine Monitor)
- virtual machine
- Virtual machine
- Source Monitor的使用
- About Virtual Machine
- Virtual Machine library
- Java Virtual Machine Launcher
- Dalvik virtual machine
- Virtual Machine Protection
- kvm virtual machine creation
- Java Virtual Machine Options
- Virtual Machine setting up
- Dalvik Virtual Machine references
- 虚拟机(Virtual Machine)
- tasklet原理
- C++的头文件和实现文件分别写什么(转)
- mongodb
- break,continue,return的区别
- POJ 1163 The Triangle
- Virtual Machine Monitor source
- H3C 产品彩页
- Building OpenCV-2.4.X for Freescale's i.MX6 BSP (LTIB)
- 如何分辨一个外链中的链接是否为高质量链接
- 编译语言与解释语言的区别
- application类的作用?
- cocos2dx—win32平台打包成akp的方法,无需安装cygwin
- NGUI纹理九宫格拉伸
- 一直困惑的DIV并列显示,原来css3可以实现,早应该去看看CSS3的手册了。