_Use_decl_annotations_ bool __stdcall VmmVmExitHandler(VmmInitialStack *stack) { // Save guest's context and raise IRQL as quick as possible const auto guest_irql = KeGetCurrentIrql(); const auto guest_cr8 = IsX64() ? __readcr8() : 0; if (guest_irql < DISPATCH_LEVEL) { KeRaiseIrqlToDpcLevel(); } NT_ASSERT(stack->reserved == MAXULONG_PTR); // Capture the current guest state GuestContext guest_context = {stack, UtilVmRead(VmcsField::kGuestRflags), UtilVmRead(VmcsField::kGuestRip), guest_cr8, guest_irql, true}; guest_context.gp_regs->sp = UtilVmRead(VmcsField::kGuestRsp); // Dispatch the current VM-exit event VmmpHandleVmExit(&guest_context); // Restore guest's context if (guest_context.irql < DISPATCH_LEVEL) { KeLowerIrql(guest_context.irql); } // Apply possibly updated CR8 by the handler if (IsX64()) { __writecr8(guest_context.cr8); } return guest_context.vm_continue; }
// Execute a non-image region as a test _Use_decl_annotations_ void MmonExecuteDoggyRegion() { PAGED_CODE(); #pragma prefast(suppress : 30030, "Allocating executable POOL_TYPE memory") auto code = reinterpret_cast<UCHAR *>(ExAllocatePoolWithTag( NonPagedPoolExecute, PAGE_SIZE, kHyperPlatformCommonPoolTag)); if (!code) { return; } RtlZeroMemory(code, PAGE_SIZE); HYPERPLATFORM_LOG_DEBUG("PoolCode = %p, Pa = %016llx", code, UtilPaFromVa(code)); code[0] = 0x90; // nop code[1] = 0x90; // nop if (IsX64()) { code[2] = 0xc3; // ret } else { code[2] = 0xc2; code[3] = 0x04; // retn 4 } KeInvalidateAllCaches(); // Runs code on all processors at once auto function = reinterpret_cast<PKIPI_BROADCAST_WORKER>(code); KeIpiGenericCall(function, 0); ExFreePoolWithTag(code, kHyperPlatformCommonPoolTag); }
// Converts a function address to a function pointer. _Use_decl_annotations_ EXTERN_C FARPROC UtilDataToFp(UCHAR *FunctionAddress) { if (IsX64()) { return reinterpret_cast<FARPROC>(FunctionAddress); } else { return reinterpret_cast<FARPROC>( reinterpret_cast<ULONG_PTR>(FunctionAddress) | 1); } }
// Converts a function pointer to a function address. _Use_decl_annotations_ EXTERN_C UCHAR *UtilFpToData(FARPROC FunctionPointer) { if (IsX64()) { return reinterpret_cast<UCHAR *>(FunctionPointer); } else { return reinterpret_cast<UCHAR *>( reinterpret_cast<ULONG_PTR>(FunctionPointer) & ~1); } }
DWORD InitDriverInfo() { OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); switch(osvi.dwPlatformId) { case VER_PLATFORM_WIN32s: gDriverType = OLS_DRIVER_TYPE_UNKNOWN; return OLS_DLL_UNSUPPORTED_PLATFORM; break; case VER_PLATFORM_WIN32_WINDOWS: _tcscpy_s(gDriverFileName, MAX_PATH, OLS_DRIVER_FILE_NAME_WIN_9X); gDriverType = OLS_DRIVER_TYPE_WIN_9X; return OLS_DLL_NO_ERROR; break; case VER_PLATFORM_WIN32_NT: #ifdef _WIN64 #ifdef _M_X64 _tcscpy_s(gDriverFileName, MAX_PATH, OLS_DRIVER_FILE_NAME_WIN_NT_X64); gDriverType = OLS_DRIVER_TYPE_WIN_NT_X64; #else // IA64 _tcscpy_s(gDriverFileName, MAX_PATH, OLS_DRIVER_FILE_NAME_WIN_NT_IA64); gDriverType = OLS_DRIVER_TYPE_WIN_NT_IA64; return OLS_DLL_UNSUPPORTED_PLATFORM; #endif #else if(IsWow64()) { if(IsX64()) { _tcscpy_s(gDriverFileName, MAX_PATH, OLS_DRIVER_FILE_NAME_WIN_NT_X64); gDriverType = OLS_DRIVER_TYPE_WIN_NT_X64; } else { _tcscpy_s(gDriverFileName, MAX_PATH, OLS_DRIVER_FILE_NAME_WIN_NT_IA64); gDriverType = OLS_DRIVER_TYPE_WIN_NT_IA64; return OLS_DLL_UNSUPPORTED_PLATFORM; } } else { _tcscpy_s(gDriverFileName, MAX_PATH, OLS_DRIVER_FILE_NAME_WIN_NT); gDriverType = OLS_DRIVER_TYPE_WIN_NT; } #endif return OLS_DLL_NO_ERROR; break; default: gDriverType = OLS_DRIVER_TYPE_UNKNOWN; return OLS_DLL_UNKNOWN_ERROR; break; } }
// Test if the system is one of supported OS versions _Use_decl_annotations_ bool DriverpIsSuppoetedOS() { PAGED_CODE(); RTL_OSVERSIONINFOW os_version = {}; auto status = RtlGetVersion(&os_version); if (!NT_SUCCESS(status)) { return false; } if (os_version.dwMajorVersion != 6 && os_version.dwMajorVersion != 10) { return false; } // 4-gigabyte tuning (4GT) should not be enabled if (!IsX64() && reinterpret_cast<ULONG_PTR>(MmSystemRangeStart) != 0x80000000) { return false; } return true; }
// Get an address of a token from a value of EPROCESS::Token, which does not // directly point to the token address. _Use_decl_annotations_ static PACCESS_TOKEN EopmonpGetProceesTokenByAddress( ULONG_PTR address) { // To get an address, the lowest N bits where N is a size of a RefCnt field // needs to be masked. const auto value = *reinterpret_cast<ULONG_PTR*>(address); if (IsX64()) { // kd> dt nt!_EX_FAST_REF // + 0x000 Object : Ptr64 Void // + 0x000 RefCnt : Pos 0, 4 Bits // + 0x000 Value : Uint8B return reinterpret_cast<PACCESS_TOKEN>(value & (static_cast<ULONG_PTR>(~0xf))); } else { // kd> dt nt!_EX_FAST_REF // + 0x000 Object : Ptr32 Void // + 0x000 RefCnt : Pos 0, 3 Bits // + 0x000 Value : Uint4B return reinterpret_cast<PACCESS_TOKEN>(value & (static_cast<ULONG_PTR>(~7))); } }
// Save a pointer size value to the registry bool RegWritePointerSize(_In_ const std::basic_string<TCHAR> &Path, _In_ const std::basic_string<TCHAR> &Name, _In_ std::uintptr_t Value) { static_assert(sizeof(Value) == sizeof(void *), "Size has to be a pointer size"); HKEY keyNaked = nullptr; auto status = ::RegCreateKeyEx(HKEY_LOCAL_MACHINE, Path.c_str(), 0, nullptr, 0, KEY_SET_VALUE, nullptr, &keyNaked, nullptr); if (!SUCCEEDED(status)) { return false; } auto key = std::experimental::make_unique_resource(std::move(keyNaked), &::RegCloseKey); auto regType = (IsX64()) ? REG_QWORD : REG_DWORD; status = ::RegSetValueEx(key.get(), Name.c_str(), 0, regType, reinterpret_cast<const BYTE *>(&Value), sizeof(Value)); return SUCCEEDED(status); }
_Use_decl_annotations_ EXTERN_C NTSTATUS UtilLoadPointerVaule(const wchar_t *Key, const wchar_t *Value, void **Data) { PAGED_CODE(); UNICODE_STRING path = {}; RtlInitUnicodeString(&path, Key); OBJECT_ATTRIBUTES oa = RTL_INIT_OBJECT_ATTRIBUTES( &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE); // Open the registry HANDLE keyNaked = nullptr; auto status = ZwOpenKey(&keyNaked, KEY_READ, &oa); if (!NT_SUCCESS(status)) { return status; } auto key = std::experimental::make_unique_resource(std::move(keyNaked), &::ZwClose); UNICODE_STRING valueName = {}; RtlInitUnicodeString(&valueName, Value); // Read value ULONG resultLength = 0; UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(void *)] = {}; status = ZwQueryValueKey(key.get(), &valueName, KeyValuePartialInformation, buffer, sizeof(buffer), &resultLength); if (!NT_SUCCESS(status)) { return status; } // Error if it is not an expected type or not a pointer size. ULONG expectedRegType = (IsX64()) ? REG_QWORD : REG_DWORD; auto data = reinterpret_cast<KEY_VALUE_PARTIAL_INFORMATION *>(buffer); if (data->Type != expectedRegType || data->DataLength != sizeof(void *)) { return STATUS_DATA_NOT_ACCEPTED; } *Data = *reinterpret_cast<void **>(data->Data); return status; }
DWORD Init() { Registry reg; auto result = reg.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", Registry::Mode::Read); if (result != ERROR_SUCCESS) { return result; } reg.TryReadString(L"CurrentBuildNumber", CurrentBuildNumber); reg.TryReadDword(L"CurrentMajorVersionNumber", CurrentMajorVersionNumber); reg.TryReadDword(L"CurrentMinorVersionNumber", CurrentMinorVersionNumber); reg.TryReadString(L"CSDbuildNumber", CSDBuildNumber); reg.TryReadString(L"CSDVersion", ServicePack); auto pos = ServicePack.find_last_not_of(L"Service Pack "); if (pos != std::wstring::npos) { ServicePack = L"SP" + ServicePack.substr(pos); } if (reg.TryReadString(L"BuildLabEx", BuildLabEx) != NO_ERROR) { reg.TryReadString(L"BuildLab", BuildLabEx); } reg.TryReadString(L"CurrentVersion", CurrentVersion); reg.TryReadString(L"EditionId", EditionId); reg.TryReadString(L"ProductName", ProductName); if (CurrentMajorVersionNumber > 0) { CurrentVersion = std::to_wstring(CurrentMajorVersionNumber) + L"." + std::to_wstring(CurrentMinorVersionNumber); } else { reg.TryReadString(L"CurrentVersion", CurrentVersion); } Architecture = IsX64() ? std::wstring(L"x64") : std::wstring(L"x86"); Language = GetDefaultLocaleName(); return ERROR_SUCCESS; }
// Locate MmPfnDatabase _Use_decl_annotations_ static NTSTATUS MmonpInitializeMmPfnDatabase() { PAGED_CODE(); RTL_OSVERSIONINFOW os_version = {}; auto status = RtlGetVersion(&os_version); if (!NT_SUCCESS(status)) { return status; } // Set appropriate patterns and based on an OS version struct MmPfnDatabaseSearchPattern { const UCHAR *bytes; SIZE_T bytes_size; bool hard_coded; }; MmPfnDatabaseSearchPattern patterns[2] = {}; if (IsX64()) { // Win 10 build 14316 is the first version implements randomized page tables if (os_version.dwMajorVersion < 10 || os_version.dwBuildNumber < 14316) { // PFN database is at the constant location on older x64 Windows g_mmonp_MmPfnDatabase = reinterpret_cast<void *>(0xfffffa8000000000); return STATUS_SUCCESS; } // Windows 10 x64 Build 14332+ static const UCHAR kPatternWin10x64[] = { 0x48, 0x8B, 0xC1, // mov rax, rcx 0x48, 0xC1, 0xE8, 0x0C, // shr rax, 0Ch 0x48, 0x8D, 0x14, 0x40, // lea rdx, [rax + rax * 2] 0x48, 0x03, 0xD2, // add rdx, rdx 0x48, 0xB8, // mov rax, 0FFFFFA8000000008h }; patterns[0].bytes = kPatternWin10x64; patterns[0].bytes_size = sizeof(kPatternWin10x64); patterns[0].hard_coded = true; } else { // x86 if (os_version.dwMajorVersion == 6 && os_version.dwMinorVersion == 1) { // Windows 7 (No PAE) static const UCHAR kPatternWin7[] = { 0x6B, 0xC0, 0x18, // imul eax, 18h 0x8B, 0x0D, // mov ecx, ds:_MmPfnDatabase }; // Windows 7 (PAE) static const UCHAR kPatternWin7Pae[] = { 0x6B, 0xC0, 0x1C, // imul eax, 1Ch 0x8B, 0x0D, // mov ecx, ds:_MmPfnDatabase }; if (UtilIsX86Pae()) { patterns[0].bytes = kPatternWin7Pae; patterns[0].bytes_size = sizeof(kPatternWin7Pae); patterns[0].hard_coded = false; } else { patterns[0].bytes = kPatternWin7; patterns[0].bytes_size = sizeof(kPatternWin7); patterns[0].hard_coded = false; } } else if ((os_version.dwMajorVersion == 6 && os_version.dwMinorVersion == 3) || (os_version.dwMajorVersion == 10 && os_version.dwMinorVersion == 0)) { // Windows 8.1 and 10 static const UCHAR kPatternWin81And10_0[] = { 0xC1, 0xF8, 0x0C, // sar eax, 0Ch 0xA1, // mov eax, ds:_MmPfnDatabase }; static const UCHAR kPatternWin81And10_1[] = { 0xC1, 0xE8, 0x0C, // shr eax, 0Ch 0xA1, // mov eax, ds:_MmPfnDatabase }; patterns[0].bytes = kPatternWin81And10_0; patterns[0].bytes_size = sizeof(kPatternWin81And10_0); patterns[0].hard_coded = false; patterns[1].bytes = kPatternWin81And10_1; patterns[1].bytes_size = sizeof(kPatternWin81And10_1); patterns[1].hard_coded = false; } else { // Unknown x86 OS version return STATUS_UNSUCCESSFUL; } } // Search the patterns from MmGetVirtualForPhysical const auto p_MmGetVirtualForPhysical = reinterpret_cast<UCHAR *>( UtilGetSystemProcAddress(L"MmGetVirtualForPhysical")); if (!p_MmGetVirtualForPhysical) { return STATUS_PROCEDURE_NOT_FOUND; } for (const auto &pattern : patterns) { if (!pattern.bytes) { break; // no more patterns } auto found = reinterpret_cast<UCHAR *>(UtilMemMem( p_MmGetVirtualForPhysical, 0x20, pattern.bytes, pattern.bytes_size)); if (!found) { continue; } // Get an address of PFN database found += pattern.bytes_size; if (pattern.hard_coded) { HYPERPLATFORM_LOG_DEBUG("Found a hard coded PFN database address at %p", found); g_mmonp_MmPfnDatabase = *reinterpret_cast<void **>(found); } else { HYPERPLATFORM_LOG_DEBUG("Found a reference to MmPfnDatabase at %p", found); const auto mmpfn_address = *reinterpret_cast<ULONG_PTR *>(found); g_mmonp_MmPfnDatabase = *reinterpret_cast<void **>(mmpfn_address); } // On Windows 10 RS, a value has 0x8. Delete it. g_mmonp_MmPfnDatabase = PAGE_ALIGN(g_mmonp_MmPfnDatabase); break; } HYPERPLATFORM_LOG_DEBUG("MmPfnDatabase = %p", g_mmonp_MmPfnDatabase); if (!g_mmonp_MmPfnDatabase) { return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; }
// See: PREPARATION AND LAUNCHING A VIRTUAL MACHINE _Use_decl_annotations_ static bool VmpSetupVMCS( const ProcessorData *processor_data, ULONG_PTR guest_stack_pointer, ULONG_PTR guest_instruction_pointer, ULONG_PTR vmm_stack_pointer) { Gdtr gdtr = {}; __sgdt(&gdtr); Idtr idtr = {}; __sidt(&idtr); // See: Algorithms for Determining VMX Capabilities const auto use_true_msrs = Ia32VmxBasicMsr{ UtilReadMsr64( Msr::kIa32VmxBasic)}.fields.vmx_capability_hint; VmxVmEntryControls vm_entryctl_requested = {}; vm_entryctl_requested.fields.ia32e_mode_guest = IsX64(); VmxVmEntryControls vm_entryctl = {VmpAdjustControlValue( (use_true_msrs) ? Msr::kIa32VmxTrueEntryCtls : Msr::kIa32VmxEntryCtls, vm_entryctl_requested.all)}; VmxVmExitControls vm_exitctl_requested = {}; vm_exitctl_requested.fields.acknowledge_interrupt_on_exit = true; vm_exitctl_requested.fields.host_address_space_size = IsX64(); VmxVmExitControls vm_exitctl = {VmpAdjustControlValue( (use_true_msrs) ? Msr::kIa32VmxTrueExitCtls : Msr::kIa32VmxExitCtls, vm_exitctl_requested.all)}; VmxPinBasedControls vm_pinctl_requested = {}; VmxPinBasedControls vm_pinctl = { VmpAdjustControlValue((use_true_msrs) ? Msr::kIa32VmxTruePinbasedCtls : Msr::kIa32VmxPinbasedCtls, vm_pinctl_requested.all)}; VmxProcessorBasedControls vm_procctl_requested = {}; vm_procctl_requested.fields.invlpg_exiting = false; vm_procctl_requested.fields.rdtsc_exiting = false; vm_procctl_requested.fields.cr3_load_exiting = true; vm_procctl_requested.fields.cr8_load_exiting = false; // NB: very frequent vm_procctl_requested.fields.mov_dr_exiting = true; vm_procctl_requested.fields.use_msr_bitmaps = true; vm_procctl_requested.fields.activate_secondary_control = true; VmxProcessorBasedControls vm_procctl = { VmpAdjustControlValue((use_true_msrs) ? Msr::kIa32VmxTrueProcBasedCtls : Msr::kIa32VmxProcBasedCtls, vm_procctl_requested.all)}; VmxSecondaryProcessorBasedControls vm_procctl2_requested = {}; vm_procctl2_requested.fields.enable_ept = true; vm_procctl2_requested.fields.enable_rdtscp = true; // required for Win10 vm_procctl2_requested.fields.descriptor_table_exiting = true; // required for Win10 vm_procctl2_requested.fields.enable_xsaves_xstors = true; VmxSecondaryProcessorBasedControls vm_procctl2 = {VmpAdjustControlValue( Msr::kIa32VmxProcBasedCtls2, vm_procctl2_requested.all)}; // Set up CR0 and CR4 bitmaps // - Where a bit is masked, the shadow bit appears // - Where a bit is not masked, the actual bit appears // VM-exit occurs when a guest modifies any of those fields Cr0 cr0_mask = {}; Cr4 cr4_mask = {}; // See: PDPTE Registers // If PAE paging would be in use following an execution of MOV to CR0 or MOV // to CR4 (see Section 4.1.1) and the instruction is modifying any of CR0.CD, // CR0.NW, CR0.PG, CR4.PAE, CR4.PGE, CR4.PSE, or CR4.SMEP; then the PDPTEs are // loaded from the address in CR3. if (UtilIsX86Pae()) { cr0_mask.fields.pg = true; cr0_mask.fields.cd = true; cr0_mask.fields.nw = true; cr4_mask.fields.pae = true; cr4_mask.fields.pge = true; cr4_mask.fields.pse = true; cr4_mask.fields.smep = true; } const auto exception_bitmap = // 1 << InterruptionVector::kBreakpointException | // 1 << InterruptionVector::kGeneralProtectionException | // 1 << InterruptionVector::kPageFaultException | 0; // clang-format off /* 16-Bit Control Field */ /* 16-Bit Guest-State Fields */ auto error = VmxStatus::kOk; error |= UtilVmWrite(VmcsField::kGuestEsSelector, AsmReadES()); error |= UtilVmWrite(VmcsField::kGuestCsSelector, AsmReadCS()); error |= UtilVmWrite(VmcsField::kGuestSsSelector, AsmReadSS()); error |= UtilVmWrite(VmcsField::kGuestDsSelector, AsmReadDS()); error |= UtilVmWrite(VmcsField::kGuestFsSelector, AsmReadFS()); error |= UtilVmWrite(VmcsField::kGuestGsSelector, AsmReadGS()); error |= UtilVmWrite(VmcsField::kGuestLdtrSelector, AsmReadLDTR()); error |= UtilVmWrite(VmcsField::kGuestTrSelector, AsmReadTR()); /* 16-Bit Host-State Fields */ // RPL and TI have to be 0 error |= UtilVmWrite(VmcsField::kHostEsSelector, AsmReadES() & 0xf8); error |= UtilVmWrite(VmcsField::kHostCsSelector, AsmReadCS() & 0xf8); error |= UtilVmWrite(VmcsField::kHostSsSelector, AsmReadSS() & 0xf8); error |= UtilVmWrite(VmcsField::kHostDsSelector, AsmReadDS() & 0xf8); error |= UtilVmWrite(VmcsField::kHostFsSelector, AsmReadFS() & 0xf8); error |= UtilVmWrite(VmcsField::kHostGsSelector, AsmReadGS() & 0xf8); error |= UtilVmWrite(VmcsField::kHostTrSelector, AsmReadTR() & 0xf8); /* 64-Bit Control Fields */ error |= UtilVmWrite64(VmcsField::kIoBitmapA, 0); error |= UtilVmWrite64(VmcsField::kIoBitmapB, 0); error |= UtilVmWrite64(VmcsField::kMsrBitmap, UtilPaFromVa(processor_data->shared_data->msr_bitmap)); error |= UtilVmWrite64(VmcsField::kEptPointer, EptGetEptPointer(processor_data->ept_data)); /* 64-Bit Guest-State Fields */ error |= UtilVmWrite64(VmcsField::kVmcsLinkPointer, MAXULONG64); error |= UtilVmWrite64(VmcsField::kGuestIa32Debugctl, UtilReadMsr64(Msr::kIa32Debugctl)); if (UtilIsX86Pae()) { UtilLoadPdptes(__readcr3()); } /* 32-Bit Control Fields */ error |= UtilVmWrite(VmcsField::kPinBasedVmExecControl, vm_pinctl.all); error |= UtilVmWrite(VmcsField::kCpuBasedVmExecControl, vm_procctl.all); error |= UtilVmWrite(VmcsField::kExceptionBitmap, exception_bitmap); error |= UtilVmWrite(VmcsField::kPageFaultErrorCodeMask, 0); error |= UtilVmWrite(VmcsField::kPageFaultErrorCodeMatch, 0); error |= UtilVmWrite(VmcsField::kCr3TargetCount, 0); error |= UtilVmWrite(VmcsField::kVmExitControls, vm_exitctl.all); error |= UtilVmWrite(VmcsField::kVmExitMsrStoreCount, 0); error |= UtilVmWrite(VmcsField::kVmExitMsrLoadCount, 0); error |= UtilVmWrite(VmcsField::kVmEntryControls, vm_entryctl.all); error |= UtilVmWrite(VmcsField::kVmEntryMsrLoadCount, 0); error |= UtilVmWrite(VmcsField::kVmEntryIntrInfoField, 0); error |= UtilVmWrite(VmcsField::kSecondaryVmExecControl, vm_procctl2.all); /* 32-Bit Guest-State Fields */ error |= UtilVmWrite(VmcsField::kGuestEsLimit, GetSegmentLimit(AsmReadES())); error |= UtilVmWrite(VmcsField::kGuestCsLimit, GetSegmentLimit(AsmReadCS())); error |= UtilVmWrite(VmcsField::kGuestSsLimit, GetSegmentLimit(AsmReadSS())); error |= UtilVmWrite(VmcsField::kGuestDsLimit, GetSegmentLimit(AsmReadDS())); error |= UtilVmWrite(VmcsField::kGuestFsLimit, GetSegmentLimit(AsmReadFS())); error |= UtilVmWrite(VmcsField::kGuestGsLimit, GetSegmentLimit(AsmReadGS())); error |= UtilVmWrite(VmcsField::kGuestLdtrLimit, GetSegmentLimit(AsmReadLDTR())); error |= UtilVmWrite(VmcsField::kGuestTrLimit, GetSegmentLimit(AsmReadTR())); error |= UtilVmWrite(VmcsField::kGuestGdtrLimit, gdtr.limit); error |= UtilVmWrite(VmcsField::kGuestIdtrLimit, idtr.limit); error |= UtilVmWrite(VmcsField::kGuestEsArBytes, VmpGetSegmentAccessRight(AsmReadES())); error |= UtilVmWrite(VmcsField::kGuestCsArBytes, VmpGetSegmentAccessRight(AsmReadCS())); error |= UtilVmWrite(VmcsField::kGuestSsArBytes, VmpGetSegmentAccessRight(AsmReadSS())); error |= UtilVmWrite(VmcsField::kGuestDsArBytes, VmpGetSegmentAccessRight(AsmReadDS())); error |= UtilVmWrite(VmcsField::kGuestFsArBytes, VmpGetSegmentAccessRight(AsmReadFS())); error |= UtilVmWrite(VmcsField::kGuestGsArBytes, VmpGetSegmentAccessRight(AsmReadGS())); error |= UtilVmWrite(VmcsField::kGuestLdtrArBytes, VmpGetSegmentAccessRight(AsmReadLDTR())); error |= UtilVmWrite(VmcsField::kGuestTrArBytes, VmpGetSegmentAccessRight(AsmReadTR())); error |= UtilVmWrite(VmcsField::kGuestInterruptibilityInfo, 0); error |= UtilVmWrite(VmcsField::kGuestActivityState, 0); error |= UtilVmWrite(VmcsField::kGuestSysenterCs, UtilReadMsr(Msr::kIa32SysenterCs)); /* 32-Bit Host-State Field */ error |= UtilVmWrite(VmcsField::kHostIa32SysenterCs, UtilReadMsr(Msr::kIa32SysenterCs)); /* Natural-Width Control Fields */ error |= UtilVmWrite(VmcsField::kCr0GuestHostMask, cr0_mask.all); error |= UtilVmWrite(VmcsField::kCr4GuestHostMask, cr4_mask.all); error |= UtilVmWrite(VmcsField::kCr0ReadShadow, __readcr0()); error |= UtilVmWrite(VmcsField::kCr4ReadShadow, __readcr4()); /* Natural-Width Guest-State Fields */ error |= UtilVmWrite(VmcsField::kGuestCr0, __readcr0()); error |= UtilVmWrite(VmcsField::kGuestCr3, __readcr3()); error |= UtilVmWrite(VmcsField::kGuestCr4, __readcr4()); #if defined(_AMD64_) error |= UtilVmWrite(VmcsField::kGuestEsBase, 0); error |= UtilVmWrite(VmcsField::kGuestCsBase, 0); error |= UtilVmWrite(VmcsField::kGuestSsBase, 0); error |= UtilVmWrite(VmcsField::kGuestDsBase, 0); error |= UtilVmWrite(VmcsField::kGuestFsBase, UtilReadMsr(Msr::kIa32FsBase)); error |= UtilVmWrite(VmcsField::kGuestGsBase, UtilReadMsr(Msr::kIa32GsBase)); #else error |= UtilVmWrite(VmcsField::kGuestEsBase, VmpGetSegmentBase(gdtr.base, AsmReadES())); error |= UtilVmWrite(VmcsField::kGuestCsBase, VmpGetSegmentBase(gdtr.base, AsmReadCS())); error |= UtilVmWrite(VmcsField::kGuestSsBase, VmpGetSegmentBase(gdtr.base, AsmReadSS())); error |= UtilVmWrite(VmcsField::kGuestDsBase, VmpGetSegmentBase(gdtr.base, AsmReadDS())); error |= UtilVmWrite(VmcsField::kGuestFsBase, VmpGetSegmentBase(gdtr.base, AsmReadFS())); error |= UtilVmWrite(VmcsField::kGuestGsBase, VmpGetSegmentBase(gdtr.base, AsmReadGS())); #endif error |= UtilVmWrite(VmcsField::kGuestLdtrBase, VmpGetSegmentBase(gdtr.base, AsmReadLDTR())); error |= UtilVmWrite(VmcsField::kGuestTrBase, VmpGetSegmentBase(gdtr.base, AsmReadTR())); error |= UtilVmWrite(VmcsField::kGuestGdtrBase, gdtr.base); error |= UtilVmWrite(VmcsField::kGuestIdtrBase, idtr.base); error |= UtilVmWrite(VmcsField::kGuestDr7, __readdr(7)); error |= UtilVmWrite(VmcsField::kGuestRsp, guest_stack_pointer); error |= UtilVmWrite(VmcsField::kGuestRip, guest_instruction_pointer); error |= UtilVmWrite(VmcsField::kGuestRflags, __readeflags()); error |= UtilVmWrite(VmcsField::kGuestSysenterEsp, UtilReadMsr(Msr::kIa32SysenterEsp)); error |= UtilVmWrite(VmcsField::kGuestSysenterEip, UtilReadMsr(Msr::kIa32SysenterEip)); /* Natural-Width Host-State Fields */ error |= UtilVmWrite(VmcsField::kHostCr0, __readcr0()); error |= UtilVmWrite(VmcsField::kHostCr3, __readcr3()); error |= UtilVmWrite(VmcsField::kHostCr4, __readcr4()); #if defined(_AMD64_) error |= UtilVmWrite(VmcsField::kHostFsBase, UtilReadMsr(Msr::kIa32FsBase)); error |= UtilVmWrite(VmcsField::kHostGsBase, UtilReadMsr(Msr::kIa32GsBase)); #else error |= UtilVmWrite(VmcsField::kHostFsBase, VmpGetSegmentBase(gdtr.base, AsmReadFS())); error |= UtilVmWrite(VmcsField::kHostGsBase, VmpGetSegmentBase(gdtr.base, AsmReadGS())); #endif error |= UtilVmWrite(VmcsField::kHostTrBase, VmpGetSegmentBase(gdtr.base, AsmReadTR())); error |= UtilVmWrite(VmcsField::kHostGdtrBase, gdtr.base); error |= UtilVmWrite(VmcsField::kHostIdtrBase, idtr.base); error |= UtilVmWrite(VmcsField::kHostIa32SysenterEsp, UtilReadMsr(Msr::kIa32SysenterEsp)); error |= UtilVmWrite(VmcsField::kHostIa32SysenterEip, UtilReadMsr(Msr::kIa32SysenterEip)); error |= UtilVmWrite(VmcsField::kHostRsp, vmm_stack_pointer); error |= UtilVmWrite(VmcsField::kHostRip, reinterpret_cast<ULONG_PTR>(AsmVmmEntryPoint)); // clang-format on const auto vmx_status = static_cast<VmxStatus>(error); return vmx_status == VmxStatus::kOk; }
// Locate MmPfnDatabase _Use_decl_annotations_ static NTSTATUS MmonpInitializeMmPfnDatabase() { PAGED_CODE(); if (IsX64()) { g_mmonp_MmPfnDatabase = reinterpret_cast<void *>(0xfffffa8000000000); } else { const auto p_MmGetVirtualForPhysical = reinterpret_cast<UCHAR *>( UtilGetSystemProcAddress(L"MmGetVirtualForPhysical")); if (!p_MmGetVirtualForPhysical) { return STATUS_PROCEDURE_NOT_FOUND; } RTL_OSVERSIONINFOW os_version = {}; auto status = RtlGetVersion(&os_version); if (!NT_SUCCESS(status)) { return status; } if (os_version.dwMajorVersion == 6 && os_version.dwMinorVersion == 1) { // Windows 7 (No PAE) // 6B C0 18 imul eax, 18h // 8B 0D 14 28 56 00 mov ecx, ds:_MmPfnDatabase static const UCHAR kPatternWin7[] = { 0x6B, 0xC0, 0x18, 0x8B, 0x0D, }; // Windows 7 (PAE) // 6B C0 1C imul eax, 1Ch // 8B 0D 14 28 56 00 mov ecx, ds:_MmPfnDatabase static const UCHAR kPatternWin7Pae[] = { 0x6B, 0xC0, 0x1C, 0x8B, 0x0D, }; const auto is_pae_enabled = Cr4{__readcr4()}.fields.pae; const auto pattern = (is_pae_enabled) ? kPatternWin7Pae : kPatternWin7; const auto size = (is_pae_enabled) ? sizeof(kPatternWin7Pae) : sizeof(kPatternWin7); auto found = reinterpret_cast<UCHAR *>( UtilMemMem(p_MmGetVirtualForPhysical, 0x20, pattern, size)); if (found) { found += size; const auto address = *reinterpret_cast<ULONG_PTR *>(found); g_mmonp_MmPfnDatabase = *reinterpret_cast<void **>(address); } } else if ((os_version.dwMajorVersion == 6 && os_version.dwMinorVersion == 3) || (os_version.dwMajorVersion == 10 && os_version.dwMinorVersion == 0)) { // Windows 8.1 and 10 // C1 F8 0C sar eax, 0Ch // A1 08 B7 62 00 mov eax, ds:_MmPfnDatabase static const UCHAR kPatternWin81And10[] = { 0xC1, 0xF8, 0x0C, 0xA1, }; auto found = reinterpret_cast<UCHAR *>( UtilMemMem(p_MmGetVirtualForPhysical, 0x20, kPatternWin81And10, sizeof(kPatternWin81And10))); if (found) { found += sizeof(kPatternWin81And10); const auto address = *reinterpret_cast<ULONG_PTR *>(found); g_mmonp_MmPfnDatabase = *reinterpret_cast<void **>(address); } } } return (g_mmonp_MmPfnDatabase) ? STATUS_SUCCESS : STATUS_PROCEDURE_NOT_FOUND; }