36 _Out_ PVOID *BaseOfImage);
40 _Must_inspect_result_ _IRQL_requires_max_(DISPATCH_LEVEL) NTKERNELAPI
42 MmAllocateContiguousNodeMemory(
43 _In_ SIZE_T NumberOfBytes,
50 decltype(MmAllocateContiguousNodeMemory);
69 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
72 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
75 _Success_(
return !=
nullptr) static PVOID NTAPI
78 _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS
94 #if defined(ALLOC_PRAGMA) 95 #pragma alloc_text(INIT, UtilInitialization) 96 #pragma alloc_text(PAGE, UtilTermination) 97 #pragma alloc_text(INIT, UtilpInitializePageTableVariables) 98 #pragma alloc_text(INIT, UtilpInitializeRtlPcToFileHeader) 99 #pragma alloc_text(INIT, UtilpInitializePhysicalMemoryRanges) 100 #pragma alloc_text(INIT, UtilpBuildPhysicalMemoryRanges) 101 #pragma alloc_text(PAGE, UtilForEachProcessor) 102 #pragma alloc_text(PAGE, UtilSleep) 103 #pragma alloc_text(PAGE, UtilGetSystemProcAddress) 141 _Use_decl_annotations_ NTSTATUS
149 if (!NT_SUCCESS(status)) {
154 if (!NT_SUCCESS(status)) {
159 if (!NT_SUCCESS(status)) {
186 RTL_OSVERSIONINFOW os_version = {
sizeof(os_version)};
187 auto status = RtlGetVersion(&os_version);
188 if (!NT_SUCCESS(status)) {
195 if (!
IsX64() || os_version.dwMajorVersion < 10 ||
196 os_version.dwBuildNumber < 14316) {
224 const auto p_MmGetVirtualForPhysical =
226 if (!p_MmGetVirtualForPhysical) {
227 return STATUS_PROCEDURE_NOT_FOUND;
230 static const UCHAR kPatternWin10x64[] = {
231 0x48, 0x8b, 0x04, 0xd0,
232 0x48, 0xc1, 0xe0, 0x19,
235 auto found =
reinterpret_cast<ULONG_PTR
>(
236 UtilMemMem(p_MmGetVirtualForPhysical, 0x30, kPatternWin10x64,
237 sizeof(kPatternWin10x64)));
239 return STATUS_PROCEDURE_NOT_FOUND;
242 found +=
sizeof(kPatternWin10x64);
245 const auto pte_base = *
reinterpret_cast<ULONG_PTR *
>(found);
246 const auto index = (pte_base >> kUtilpPxiShift) & kUtilpPxiMask;
247 const auto pde_base = pte_base | (index << kUtilpPpiShift);
248 const auto ppe_base = pde_base | (index << kUtilpPdiShift);
249 const auto pxe_base = ppe_base | (index << kUtilpPtiShift);
270 PDRIVER_OBJECT driver_object) {
274 const auto p_RtlPcToFileHeader =
276 if (p_RtlPcToFileHeader) {
279 return STATUS_SUCCESS;
283 #pragma warning(push) 284 #pragma warning(disable : 28175) 291 return STATUS_SUCCESS;
296 _Use_decl_annotations_
static PVOID NTAPI
298 if (pc_value < MmSystemRangeStart) {
303 for (
auto current = head->Flink; current != head; current = current->Flink) {
306 const auto driver_end =
reinterpret_cast<void *
>(
307 reinterpret_cast<ULONG_PTR
>(module->dll_base) + module->size_of_image);
309 *base_of_image = module->dll_base;
310 return module->dll_base;
318 void *base =
nullptr;
328 return STATUS_UNSUCCESSFUL;
333 for (
auto i = 0ul; i < ranges->number_of_runs; ++i) {
334 const auto base_addr =
335 static_cast<ULONG64
>(ranges->run[i].base_page) * PAGE_SIZE;
338 base_addr + ranges->run[i].page_count * PAGE_SIZE);
342 static_cast<ULONG64
>(ranges->number_of_pages) * PAGE_SIZE;
345 return STATUS_SUCCESS;
353 const auto pm_ranges = MmGetPhysicalMemoryRanges();
358 PFN_COUNT number_of_runs = 0;
359 PFN_NUMBER number_of_pages = 0;
360 for (; ; ++number_of_runs) {
361 const auto range = &pm_ranges[number_of_runs];
362 if (!range->BaseAddress.QuadPart && !range->NumberOfBytes.QuadPart) {
366 static_cast<PFN_NUMBER
>(BYTES_TO_PAGES(range->NumberOfBytes.QuadPart));
368 if (number_of_runs == 0) {
369 ExFreePoolWithTag(pm_ranges,
'hPmM');
373 const auto memory_block_size =
376 const auto pm_block =
380 ExFreePoolWithTag(pm_ranges,
'hPmM');
383 RtlZeroMemory(pm_block, memory_block_size);
385 pm_block->number_of_runs = number_of_runs;
386 pm_block->number_of_pages = number_of_pages;
388 for (
auto run_index = 0ul; run_index < number_of_runs; run_index++) {
389 auto current_run = &pm_block->run[run_index];
390 auto current_block = &pm_ranges[run_index];
391 current_run->base_page =
static_cast<ULONG_PTR
>(
393 current_run->page_count =
static_cast<ULONG_PTR
>(
394 BYTES_TO_PAGES(current_block->NumberOfBytes.QuadPart));
397 ExFreePoolWithTag(pm_ranges,
'hPmM');
411 _Use_decl_annotations_ NTSTATUS
415 const auto number_of_processors =
416 KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
417 for (ULONG processor_index = 0; processor_index < number_of_processors;
419 PROCESSOR_NUMBER processor_number = {};
421 KeGetProcessorNumberFromIndex(processor_index, &processor_number);
422 if (!NT_SUCCESS(status)) {
427 GROUP_AFFINITY affinity = {};
428 affinity.Group = processor_number.Group;
429 affinity.Mask = 1ull << processor_number.Number;
430 GROUP_AFFINITY previous_affinity = {};
431 KeSetSystemGroupAffinityThread(&affinity, &previous_affinity);
434 status = callback_routine(context);
436 KeRevertToUserGroupAffinityThread(&previous_affinity);
437 if (!NT_SUCCESS(status)) {
441 return STATUS_SUCCESS;
446 _Use_decl_annotations_ NTSTATUS
448 const auto number_of_processors =
449 KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
450 for (ULONG processor_index = 0; processor_index < number_of_processors;
452 PROCESSOR_NUMBER processor_number = {};
454 KeGetProcessorNumberFromIndex(processor_index, &processor_number);
455 if (!NT_SUCCESS(status)) {
459 const auto dpc =
reinterpret_cast<PRKDPC
>(ExAllocatePoolWithTag(
462 return STATUS_MEMORY_NOT_ALLOCATED;
464 KeInitializeDpc(dpc, deferred_routine, context);
465 KeSetImportanceDpc(dpc, HighImportance);
466 status = KeSetTargetProcessorDpcEx(dpc, &processor_number);
467 if (!NT_SUCCESS(status)) {
471 KeInsertQueueDpc(dpc,
nullptr,
nullptr);
473 return STATUS_SUCCESS;
477 _Use_decl_annotations_ NTSTATUS
UtilSleep(LONG Millisecond) {
480 LARGE_INTEGER interval = {};
481 interval.QuadPart = -(10000 * Millisecond);
482 return KeDelayExecutionThread(KernelMode, FALSE, &interval);
486 _Use_decl_annotations_
void *
UtilMemMem(
const void *search_base,
487 SIZE_T search_size,
const void *pattern,
488 SIZE_T pattern_size) {
489 if (pattern_size > search_size) {
492 auto base =
static_cast<const char *
>(search_base);
493 for (SIZE_T i = 0; i <= search_size - pattern_size; i++) {
494 if (RtlCompareMemory(pattern, &base[i], pattern_size) == pattern_size) {
495 return const_cast<char *
>(&base[i]);
503 const wchar_t *proc_name) {
506 UNICODE_STRING proc_name_U = {};
507 RtlInitUnicodeString(&proc_name_U, proc_name);
508 return MmGetSystemRoutineAddress(&proc_name_U);
525 if (!pxe->valid || !ppe->valid) {
535 if (pde->large_page) {
538 if (!pte || !pte->valid) {
549 return !
UtilIsInBounds(0x0000800000000000ull, 0xffff7fffffffffffull,
550 reinterpret_cast<ULONG64>(address));
555 const void *address) {
556 const auto addr =
reinterpret_cast<ULONG_PTR
>(address);
558 const auto offset = pxe_index *
sizeof(HardwarePte);
564 const void *address) {
565 const auto addr =
reinterpret_cast<ULONG_PTR
>(address);
567 const auto offset = ppe_index *
sizeof(HardwarePte);
573 const void *address) {
574 const auto addr =
reinterpret_cast<ULONG_PTR
>(address);
576 const auto offset = pde_index *
sizeof(HardwarePte);
582 const void *address) {
583 const auto addr =
reinterpret_cast<ULONG_PTR
>(address);
585 const auto offset = pte_index *
sizeof(HardwarePte);
591 const auto pa = MmGetPhysicalAddress(va);
602 return static_cast<PFN_NUMBER
>(pa >> PAGE_SHIFT);
607 PHYSICAL_ADDRESS pa2 = {};
609 return MmGetVirtualForPhysical(pa2);
614 return static_cast<ULONG64
>(pfn) << PAGE_SHIFT;
624 SIZE_T number_of_bytes) {
625 PHYSICAL_ADDRESS highest_acceptable_address = {};
626 highest_acceptable_address.QuadPart = -1;
629 PHYSICAL_ADDRESS lowest_acceptable_address = {};
630 PHYSICAL_ADDRESS boundary_address_multiple = {};
632 number_of_bytes, lowest_acceptable_address, highest_acceptable_address,
633 boundary_address_multiple, PAGE_READWRITE, MM_ANY_NODE_OK);
635 #pragma warning(push) 636 #pragma warning(disable : 30029) 637 return MmAllocateContiguousMemory(number_of_bytes,
638 highest_acceptable_address);
645 MmFreeContiguousMemory(base_address);
652 const auto vmx_status =
static_cast<VmxStatus>(
653 AsmVmxCall(static_cast<ULONG>(hypercall_number), context));
655 : STATUS_UNSUCCESSFUL;
657 #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "Catch all."); 658 } __except (EXCEPTION_EXECUTE_HANDLER) {
659 const auto status = GetExceptionCode();
668 ULONG_PTR stack_pointer) {
669 const auto current_irql = KeGetCurrentIrql();
670 if (current_irql < DISPATCH_LEVEL) {
671 KeRaiseIrqlToDpcLevel();
677 "rax= %016Ix rbx= %016Ix rcx= %016Ix " 678 "rdx= %016Ix rsi= %016Ix rdi= %016Ix " 679 "rsp= %016Ix rbp= %016Ix " 680 " r8= %016Ix r9= %016Ix r10= %016Ix " 681 "r11= %016Ix r12= %016Ix r13= %016Ix " 682 "r14= %016Ix r15= %016Ix efl= %08Ix",
683 _ReturnAddress(), all_regs->
gp.
ax, all_regs->
gp.
bx, all_regs->
gp.
cx,
684 all_regs->
gp.
dx, all_regs->
gp.
si, all_regs->
gp.
di, stack_pointer,
685 all_regs->
gp.
bp, all_regs->
gp.r8, all_regs->
gp.r9, all_regs->
gp.r10,
686 all_regs->
gp.r11, all_regs->
gp.r12, all_regs->
gp.r13, all_regs->
gp.r14,
691 "eax= %08Ix ebx= %08Ix ecx= %08Ix " 692 "edx= %08Ix esi= %08Ix edi= %08Ix " 693 "esp= %08Ix ebp= %08Ix efl= %08x",
694 _ReturnAddress(), all_regs->
gp.
ax, all_regs->
gp.
bx, all_regs->
gp.
cx,
695 all_regs->
gp.
dx, all_regs->
gp.
si, all_regs->
gp.
di, stack_pointer,
699 if (current_irql < DISPATCH_LEVEL) {
700 KeLowerIrql(current_irql);
706 size_t field_value = 0;
707 const auto vmx_status =
static_cast<VmxStatus>(
708 __vmx_vmread(static_cast<size_t>(field), &field_value));
712 static_cast<ULONG_PTR>(vmx_status), static_cast<ULONG_PTR>(field), 0);
726 NT_ASSERT((static_cast<ULONG>(field) % 2) == 0);
728 ULARGE_INTEGER value64 = {};
731 UtilVmRead(static_cast<VmcsField>(static_cast<ULONG>(field) + 1));
732 return value64.QuadPart;
738 ULONG_PTR field_value) {
740 __vmx_vmwrite(static_cast<size_t>(field), field_value));
745 ULONG64 field_value) {
753 NT_ASSERT((static_cast<ULONG>(field) % 2) == 0);
755 ULARGE_INTEGER value64 = {};
756 value64.QuadPart = field_value;
757 const auto vmx_status =
UtilVmWrite(field, value64.LowPart);
761 return UtilVmWrite(static_cast<VmcsField>(static_cast<ULONG>(field) + 1),
768 return static_cast<ULONG_PTR
>(__readmsr(static_cast<unsigned long>(msr)));
773 return __readmsr(static_cast<unsigned long>(msr));
778 __writemsr(static_cast<unsigned long>(msr), value);
783 __writemsr(static_cast<unsigned long>(msr), value);
829 const auto current_cr3 = __readcr3();
832 __writecr3(cr3_value);
836 for (
auto i = 0ul; i < 4; ++i) {
843 __writecr3(current_cr3);
854 auto mdl = IoAllocateMdl(destination, static_cast<ULONG>(length), FALSE,
857 return STATUS_INSUFFICIENT_RESOURCES;
859 MmBuildMdlForNonPagedPool(mdl);
861 #pragma warning(push) 862 #pragma warning(disable : 28145) 875 mdl->MdlFlags &= ~MDL_SOURCE_IS_NONPAGED_POOL;
876 mdl->MdlFlags |= MDL_PAGES_LOCKED;
879 const auto writable_dest =
880 MmMapLockedPagesSpecifyCache(mdl, KernelMode, MmCached,
nullptr, FALSE,
881 NormalPagePriority | MdlMappingNoExecute);
882 if (!writable_dest) {
884 return STATUS_INSUFFICIENT_RESOURCES;
886 RtlCopyMemory(writable_dest, source, length);
887 MmUnmapLockedPages(writable_dest, mdl);
889 return STATUS_SUCCESS;
static ULONG_PTR g_utilp_pxi_mask
static MmAllocateContiguousNodeMemoryType * g_utilp_MmAllocateContiguousNodeMemory
HypercallNumber
Available command numbers for VMCALL.
ULONG64 UtilPaFromPfn(PFN_NUMBER pfn)
static HardwarePte * UtilpAddressToPde(_In_ const void *address)
#define HYPERPLATFORM_LOG_DEBUG(format,...)
Logs a message as respective severity.
static ULONG_PTR g_utilp_pti_shift
VmxStatus UtilVmWrite(VmcsField field, ULONG_PTR field_value)
NTKERNELAPI _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS HighestAcceptableAddress
VmxStatus
Indicates a result of VMX-instructions.
static NTSTATUS UtilpInitializePhysicalMemoryRanges()
unsigned pae
[5] Physical Address Extension
PFN_NUMBER UtilPfnFromVa(void *va)
static ULONG_PTR g_utilp_pdi_shift
static const auto kUtilpPtiMaskPae
bool UtilIsAccessibleAddress(void *address)
#define HYPERPLATFORM_COMMON_BUG_CHECK(hp_bug_check_code, param1, param2, param3)
Issues a bug check.
static const ULONG kHyperPlatformCommonPoolTag
A pool tag.
constexpr bool IsX64()
Checks if a system is x64.
static ULONG_PTR g_utilp_pti_mask
#define HYPERPLATFORM_COMMON_DBG_BREAK()
Sets a break point that works only when a debugger is present.
NTKERNELAPI _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS _In_opt_ PHYSICAL_ADDRESS BoundaryAddressMultiple
NTKERNELAPI _In_ PHYSICAL_ADDRESS LowestAcceptableAddress
void * UtilVaFromPa(ULONG64 pa)
LIST_ENTRY in_initialization_order_links
const PhysicalMemoryDescriptor * UtilGetPhysicalMemoryRanges()
Returns ranges of physical memory on the system.
NTKERNELAPI _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS _In_opt_ PHYSICAL_ADDRESS _In_ ULONG Protect
static PVOID NTAPI UtilpUnsafePcToFileHeader(_In_ PVOID pc_value, _Out_ PVOID *base_of_image)
static const auto kUtilpUseRtlPcToFileHeader
static HardwarePte * UtilpAddressToPte(_In_ const void *address)
static bool UtilpIsCanonicalFormAddress(_In_ void *address)
static RtlPcToFileHeaderType * g_utilp_RtlPcToFileHeader
NTKERNELAPI PVOID NTAPI RtlPcToFileHeader(_In_ PVOID PcValue, _Out_ PVOID *BaseOfImage)
NTSTATUS UtilForEachProcessorDpc(PKDEFERRED_ROUTINE deferred_routine, void *context)
void UtilWriteMsr(Msr msr, ULONG_PTR value)
void * UtilAllocateContiguousMemory(SIZE_T number_of_bytes)
ULONG64 UtilVmRead64(VmcsField field)
Represents a physical memory ranges of the system.
void UtilTermination()
Frees all resources allocated for the sake of the Util functions.
void * UtilMemMem(const void *search_base, SIZE_T search_size, const void *pattern, SIZE_T pattern_size)
void * UtilVaFromPfn(PFN_NUMBER pfn)
static ULONG_PTR g_utilp_pte_base
VmxStatus UtilInvvpidIndividualAddress(USHORT vpid, void *address)
VmxStatus UtilInveptGlobal()
Executes the INVEPT instruction and invalidates EPT entry cache.
VmxStatus UtilInvvpidSingleContextExceptGlobal(USHORT vpid)
Defines page table related constants.
static const auto kUtilpPdiShiftPae
void * UtilGetSystemProcAddress(const wchar_t *proc_name)
unsigned char __stdcall AsmVmxCall(_In_ ULONG_PTR hypercall_number, _In_opt_ void *context)
Executes VMCALL with the given hypercall number and a context.
static ULONG_PTR g_utilp_pxe_base
NTSTATUS UtilVmCall(HypercallNumber hypercall_number, void *context)
void UtilWriteMsr64(Msr msr, ULONG64 value)
void UtilDumpGpRegisters(const AllRegisters *all_regs, ULONG_PTR stack_pointer)
static NTSTATUS UtilpInitializeRtlPcToFileHeader(_In_ PDRIVER_OBJECT driver_object)
static ULONG_PTR g_utilp_pxi_shift
Declares interfaces to assembly functions.
static const auto kUtilpPdiMaskPae
void * UtilPcToFileHeader(void *pc_value)
Msr
See: MODEL-SPECIFIC REGISTERS (MSRS)
static NTSTATUS UtilpInitializePageTableVariables()
unsigned char __stdcall AsmInvept(_In_ InvEptType invept_type, _In_ const InvEptDescriptor *invept_descriptor)
Invalidates translations derived from EPT.
Declares interfaces to utility functions.
ULONG64 UtilPaFromVa(void *va)
ULONG_PTR UtilReadMsr(Msr msr)
VmcsField
See: FIELD ENCODING IN VMCS.
UNICODE_STRING full_dll_name
VmxStatus UtilInvvpidSingleContext(USHORT vpid)
static const auto kUtilpPteBasePae
Represents ranges of addresses.
ULONG64 page_directory_pa
[12:52]
static ULONG_PTR g_utilp_pde_base
#define HYPERPLATFORM_LOG_WARN_SAFE(format,...)
VMRESUME or VMXOFF has failed.
void UtilLoadPdptes(ULONG_PTR cr3_value)
NTSTATUS UtilSleep(LONG Millisecond)
#define HYPERPLATFORM_LOG_DEBUG_SAFE(format,...)
Buffers a message as respective severity.
static HardwarePte * UtilpAddressToPpe(_In_ const void *address)
LIST_ENTRY in_memory_order_links
unsigned char __stdcall AsmInvvpid(_In_ InvVpidType invvpid_type, _In_ const InvVpidDescriptor *invvpid_descriptor)
Invalidate translations based on VPID.
VmxStatus UtilInvvpidAllContext()
Executes the INVVPID instruction (type 2)
struct PdptrRegister::@12 fields
ULONG_PTR UtilVmRead(VmcsField field)
bool UtilIsX86Pae()
Checks if the system is a PAE-enabled x86 system.
NTKERNELAPI _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS _In_opt_ PHYSICAL_ADDRESS _In_ ULONG _In_ NODE_REQUIREMENT PreferredNode
NTSTATUS UtilForceCopyMemory(void *destination, const void *source, SIZE_T length)
static ULONG_PTR g_utilp_pdi_mask
static PhysicalMemoryDescriptor * g_utilp_physical_memory_ranges
void UtilFreeContiguousMemory(void *base_address)
static ULONG_PTR g_utilp_ppi_shift
static ULONG_PTR g_utilp_ppe_base
Declares and implements common things across the project.
static const auto kUtilpPtiShiftPae
decltype(MmAllocateContiguousNodeMemory) MmAllocateContiguousNodeMemoryType
LIST_ENTRY in_load_order_links
static PhysicalMemoryDescriptor * UtilpBuildPhysicalMemoryRanges()
ULONG64 UtilReadMsr64(Msr msr)
NTSTATUS UtilInitialization(PDRIVER_OBJECT driver_object)
NTKERNELAPI _Post_writable_byte_size_(NumberOfBytes)) PVOID MmAllocateContiguousNodeMemory(_In_ SIZE_T NumberOfBytes
static const auto kUtilpPdeBasePae
static HardwarePte * UtilpAddressToPxe(_In_ const void *address)
Declares interfaces to logging functions.
static LIST_ENTRY * g_utilp_PsLoadedModuleList
constexpr bool UtilIsInBounds(_In_ const T &value, _In_ const T &min, _In_ const T &max)
Tests if value is in between min and max.
PFN_NUMBER UtilPfnFromPa(ULONG64 pa)
decltype(RtlPcToFileHeader) RtlPcToFileHeaderType
static ULONG_PTR g_utilp_ppi_mask
NTSTATUS UtilForEachProcessor(NTSTATUS(*callback_routine)(void *), void *context)
Represents a stack layout after a sequence of PUSHFx, PUSHAx.
VmxStatus UtilVmWrite64(VmcsField field, ULONG64 field_value)