HyperPlatform Programmer's Reference
util.cpp
Go to the documentation of this file.
1 // Copyright (c) 2015-2018, Satoshi Tanda. All rights reserved.
2 // Use of this source code is governed by a MIT-style license that can be
3 // found in the LICENSE file.
4 
7 
8 #include "util.h"
9 #include <intrin.h>
10 #include "asm.h"
11 #include "common.h"
12 #include "log.h"
13 
14 extern "C" {
16 //
17 // macro utilities
18 //
19 
21 //
22 // constants and macros
23 //
24 
25 // Use RtlPcToFileHeader if available. Using the API causes a broken font bug
26 // on the 64 bit Windows 10 and should be avoided. This flag exist for only
27 // further investigation.
28 static const auto kUtilpUseRtlPcToFileHeader = false;
29 
31 //
32 // types
33 //
34 
35 NTKERNELAPI PVOID NTAPI RtlPcToFileHeader(_In_ PVOID PcValue,
36  _Out_ PVOID *BaseOfImage);
37 
39 
40 _Must_inspect_result_ _IRQL_requires_max_(DISPATCH_LEVEL) NTKERNELAPI
41  _When_(return != NULL, _Post_writable_byte_size_(NumberOfBytes)) PVOID
42  MmAllocateContiguousNodeMemory(
43  _In_ SIZE_T NumberOfBytes,
44  _In_ PHYSICAL_ADDRESS LowestAcceptableAddress,
45  _In_ PHYSICAL_ADDRESS HighestAcceptableAddress,
46  _In_opt_ PHYSICAL_ADDRESS BoundaryAddressMultiple, _In_ ULONG Protect,
47  _In_ NODE_REQUIREMENT PreferredNode);
48 
50  decltype(MmAllocateContiguousNodeMemory);
51 
52 // dt nt!_LDR_DATA_TABLE_ENTRY
54  LIST_ENTRY in_load_order_links;
57  void *dll_base;
58  void *entry_point;
60  UNICODE_STRING full_dll_name;
61  // ...
62 };
63 
65 //
66 // prototypes
67 //
68 
69 _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS
71 
72 _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS
73  UtilpInitializeRtlPcToFileHeader(_In_ PDRIVER_OBJECT driver_object);
74 
75 _Success_(return != nullptr) static PVOID NTAPI
76  UtilpUnsafePcToFileHeader(_In_ PVOID pc_value, _Out_ PVOID *base_of_image);
77 
78 _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS
80 
81 _IRQL_requires_max_(PASSIVE_LEVEL) static PhysicalMemoryDescriptor
83 
84 static bool UtilpIsCanonicalFormAddress(_In_ void *address);
85 
86 static HardwarePte *UtilpAddressToPxe(_In_ const void *address);
87 
88 static HardwarePte *UtilpAddressToPpe(_In_ const void *address);
89 
90 static HardwarePte *UtilpAddressToPde(_In_ const void *address);
91 
92 static HardwarePte *UtilpAddressToPte(_In_ const void *address);
93 
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)
104 #endif
105 
107 //
108 // variables
109 //
110 
112 
113 static LIST_ENTRY *g_utilp_PsLoadedModuleList;
114 
116 
119 
120 static ULONG_PTR g_utilp_pxe_base = 0;
121 static ULONG_PTR g_utilp_ppe_base = 0;
122 static ULONG_PTR g_utilp_pde_base = 0;
123 static ULONG_PTR g_utilp_pte_base = 0;
124 
125 static ULONG_PTR g_utilp_pxi_shift = 0;
126 static ULONG_PTR g_utilp_ppi_shift = 0;
127 static ULONG_PTR g_utilp_pdi_shift = 0;
128 static ULONG_PTR g_utilp_pti_shift = 0;
129 
130 static ULONG_PTR g_utilp_pxi_mask = 0;
131 static ULONG_PTR g_utilp_ppi_mask = 0;
132 static ULONG_PTR g_utilp_pdi_mask = 0;
133 static ULONG_PTR g_utilp_pti_mask = 0;
134 
136 //
137 // implementations
138 //
139 
140 // Initializes utility functions
141 _Use_decl_annotations_ NTSTATUS
142 UtilInitialization(PDRIVER_OBJECT driver_object) {
143  PAGED_CODE();
144 
145  auto status = UtilpInitializePageTableVariables();
146  HYPERPLATFORM_LOG_DEBUG("PXE at %016Ix, PPE at %016Ix, PDE at %016Ix, PTE at %016Ix",
149  if (!NT_SUCCESS(status)) {
150  return status;
151  }
152 
153  status = UtilpInitializeRtlPcToFileHeader(driver_object);
154  if (!NT_SUCCESS(status)) {
155  return status;
156  }
157 
159  if (!NT_SUCCESS(status)) {
160  return status;
161  }
162 
164  reinterpret_cast<MmAllocateContiguousNodeMemoryType *>(
165  UtilGetSystemProcAddress(L"MmAllocateContiguousNodeMemory"));
166  return status;
167 }
168 
169 // Terminates utility functions
170 _Use_decl_annotations_ void UtilTermination() {
171  PAGED_CODE();
172 
174  ExFreePoolWithTag(g_utilp_physical_memory_ranges,
176  }
177 }
178 
179 // Initializes g_utilp_p*e_base, g_utilp_p*i_shift and g_utilp_p*i_mask.
180 _Use_decl_annotations_ static NTSTATUS UtilpInitializePageTableVariables() {
181  PAGED_CODE();
182 
183 #include "util_page_constants.h" // Include platform dependent constants
184 
185  // Check OS version to know if page table base addresses need to be relocated
186  RTL_OSVERSIONINFOW os_version = {sizeof(os_version)};
187  auto status = RtlGetVersion(&os_version);
188  if (!NT_SUCCESS(status)) {
189  return status;
190  }
191 
192  // Win 10 build 14316 is the first version implements randomized page tables
193  // Use fixed values if a systems is either: x86, older than Windows 7, or
194  // older than build 14316.
195  if (!IsX64() || os_version.dwMajorVersion < 10 ||
196  os_version.dwBuildNumber < 14316) {
197  if (IsX64()) {
198  g_utilp_pxe_base = kUtilpPxeBase;
199  g_utilp_ppe_base = kUtilpPpeBase;
200  g_utilp_pxi_shift = kUtilpPxiShift;
201  g_utilp_ppi_shift = kUtilpPpiShift;
202  g_utilp_pxi_mask = kUtilpPxiMask;
203  g_utilp_ppi_mask = kUtilpPpiMask;
204  }
205  if (UtilIsX86Pae()) {
212  } else {
213  g_utilp_pde_base = kUtilpPdeBase;
214  g_utilp_pte_base = kUtilpPteBase;
215  g_utilp_pdi_shift = kUtilpPdiShift;
216  g_utilp_pti_shift = kUtilpPtiShift;
217  g_utilp_pdi_mask = kUtilpPdiMask;
218  g_utilp_pti_mask = kUtilpPtiMask;
219  }
220  return status;
221  }
222 
223  // Get PTE_BASE from MmGetVirtualForPhysical
224  const auto p_MmGetVirtualForPhysical =
225  UtilGetSystemProcAddress(L"MmGetVirtualForPhysical");
226  if (!p_MmGetVirtualForPhysical) {
227  return STATUS_PROCEDURE_NOT_FOUND;
228  }
229 
230  static const UCHAR kPatternWin10x64[] = {
231  0x48, 0x8b, 0x04, 0xd0, // mov rax, [rax+rdx*8]
232  0x48, 0xc1, 0xe0, 0x19, // shl rax, 19h
233  0x48, 0xba, // mov rdx, ????????`???????? ; PTE_BASE
234  };
235  auto found = reinterpret_cast<ULONG_PTR>(
236  UtilMemMem(p_MmGetVirtualForPhysical, 0x30, kPatternWin10x64,
237  sizeof(kPatternWin10x64)));
238  if (!found) {
239  return STATUS_PROCEDURE_NOT_FOUND;
240  }
241 
242  found += sizeof(kPatternWin10x64);
243  HYPERPLATFORM_LOG_DEBUG("Found a hard coded PTE_BASE at %016Ix", found);
244 
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);
250 
251  g_utilp_pxe_base = static_cast<ULONG_PTR>(pxe_base);
252  g_utilp_ppe_base = static_cast<ULONG_PTR>(ppe_base);
253  g_utilp_pde_base = static_cast<ULONG_PTR>(pde_base);
254  g_utilp_pte_base = static_cast<ULONG_PTR>(pte_base);
255 
256  g_utilp_pxi_shift = kUtilpPxiShift;
257  g_utilp_ppi_shift = kUtilpPpiShift;
258  g_utilp_pdi_shift = kUtilpPdiShift;
259  g_utilp_pti_shift = kUtilpPtiShift;
260 
261  g_utilp_pxi_mask = kUtilpPxiMask;
262  g_utilp_ppi_mask = kUtilpPpiMask;
263  g_utilp_pdi_mask = kUtilpPdiMask;
264  g_utilp_pti_mask = kUtilpPtiMask;
265  return status;
266 }
267 
268 // Locates RtlPcToFileHeader
269 _Use_decl_annotations_ static NTSTATUS UtilpInitializeRtlPcToFileHeader(
270  PDRIVER_OBJECT driver_object) {
271  PAGED_CODE();
272 
274  const auto p_RtlPcToFileHeader =
275  UtilGetSystemProcAddress(L"RtlPcToFileHeader");
276  if (p_RtlPcToFileHeader) {
278  reinterpret_cast<RtlPcToFileHeaderType *>(p_RtlPcToFileHeader);
279  return STATUS_SUCCESS;
280  }
281  }
282 
283 #pragma warning(push)
284 #pragma warning(disable : 28175)
285  auto module =
286  reinterpret_cast<LdrDataTableEntry *>(driver_object->DriverSection);
287 #pragma warning(pop)
288 
289  g_utilp_PsLoadedModuleList = module->in_load_order_links.Flink;
291  return STATUS_SUCCESS;
292 }
293 
294 // A fake RtlPcToFileHeader without acquiring PsLoadedModuleSpinLock. Thus, it
295 // is unsafe and should be updated if we can locate PsLoadedModuleSpinLock.
296 _Use_decl_annotations_ static PVOID NTAPI
297 UtilpUnsafePcToFileHeader(PVOID pc_value, PVOID *base_of_image) {
298  if (pc_value < MmSystemRangeStart) {
299  return nullptr;
300  }
301 
302  const auto head = g_utilp_PsLoadedModuleList;
303  for (auto current = head->Flink; current != head; current = current->Flink) {
304  const auto module =
305  CONTAINING_RECORD(current, LdrDataTableEntry, in_load_order_links);
306  const auto driver_end = reinterpret_cast<void *>(
307  reinterpret_cast<ULONG_PTR>(module->dll_base) + module->size_of_image);
308  if (UtilIsInBounds(pc_value, module->dll_base, driver_end)) {
309  *base_of_image = module->dll_base;
310  return module->dll_base;
311  }
312  }
313  return nullptr;
314 }
315 
316 // A wrapper of RtlPcToFileHeader
317 _Use_decl_annotations_ void *UtilPcToFileHeader(void *pc_value) {
318  void *base = nullptr;
319  return g_utilp_RtlPcToFileHeader(pc_value, &base);
320 }
321 
322 // Initializes the physical memory ranges
323 _Use_decl_annotations_ static NTSTATUS UtilpInitializePhysicalMemoryRanges() {
324  PAGED_CODE();
325 
326  const auto ranges = UtilpBuildPhysicalMemoryRanges();
327  if (!ranges) {
328  return STATUS_UNSUCCESSFUL;
329  }
330 
332 
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;
336  HYPERPLATFORM_LOG_DEBUG("Physical Memory Range: %016llx - %016llx",
337  base_addr,
338  base_addr + ranges->run[i].page_count * PAGE_SIZE);
339  }
340 
341  const auto pm_size =
342  static_cast<ULONG64>(ranges->number_of_pages) * PAGE_SIZE;
343  HYPERPLATFORM_LOG_DEBUG("Physical Memory Total: %llu KB", pm_size / 1024);
344 
345  return STATUS_SUCCESS;
346 }
347 
348 // Builds the physical memory ranges
349 _Use_decl_annotations_ static PhysicalMemoryDescriptor *
351  PAGED_CODE();
352 
353  const auto pm_ranges = MmGetPhysicalMemoryRanges();
354  if (!pm_ranges) {
355  return nullptr;
356  }
357 
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) {
363  break;
364  }
365  number_of_pages +=
366  static_cast<PFN_NUMBER>(BYTES_TO_PAGES(range->NumberOfBytes.QuadPart));
367  }
368  if (number_of_runs == 0) {
369  ExFreePoolWithTag(pm_ranges, 'hPmM');
370  return nullptr;
371  }
372 
373  const auto memory_block_size =
374  sizeof(PhysicalMemoryDescriptor) +
375  sizeof(PhysicalMemoryRun) * (number_of_runs - 1);
376  const auto pm_block =
377  reinterpret_cast<PhysicalMemoryDescriptor *>(ExAllocatePoolWithTag(
378  NonPagedPool, memory_block_size, kHyperPlatformCommonPoolTag));
379  if (!pm_block) {
380  ExFreePoolWithTag(pm_ranges, 'hPmM');
381  return nullptr;
382  }
383  RtlZeroMemory(pm_block, memory_block_size);
384 
385  pm_block->number_of_runs = number_of_runs;
386  pm_block->number_of_pages = number_of_pages;
387 
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>(
392  UtilPfnFromPa(current_block->BaseAddress.QuadPart));
393  current_run->page_count = static_cast<ULONG_PTR>(
394  BYTES_TO_PAGES(current_block->NumberOfBytes.QuadPart));
395  }
396 
397  ExFreePoolWithTag(pm_ranges, 'hPmM');
398  return pm_block;
399 }
400 
401 // Returns the physical memory ranges
402 /*_Use_decl_annotations_*/ const PhysicalMemoryDescriptor *
405 }
406 
407 // Execute a given callback routine on all processors in PASSIVE_LEVEL. Returns
408 // STATUS_SUCCESS when all callback returned STATUS_SUCCESS as well. When
409 // one of callbacks returns anything but STATUS_SUCCESS, this function stops
410 // to call remaining callbacks and returns the value.
411 _Use_decl_annotations_ NTSTATUS
412 UtilForEachProcessor(NTSTATUS (*callback_routine)(void *), void *context) {
413  PAGED_CODE();
414 
415  const auto number_of_processors =
416  KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
417  for (ULONG processor_index = 0; processor_index < number_of_processors;
418  processor_index++) {
419  PROCESSOR_NUMBER processor_number = {};
420  auto status =
421  KeGetProcessorNumberFromIndex(processor_index, &processor_number);
422  if (!NT_SUCCESS(status)) {
423  return status;
424  }
425 
426  // Switch the current processor
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);
432 
433  // Execute callback
434  status = callback_routine(context);
435 
436  KeRevertToUserGroupAffinityThread(&previous_affinity);
437  if (!NT_SUCCESS(status)) {
438  return status;
439  }
440  }
441  return STATUS_SUCCESS;
442 }
443 
444 // Queues a given DPC routine on all processors. Returns STATUS_SUCCESS when DPC
445 // is queued for all processors.
446 _Use_decl_annotations_ NTSTATUS
447 UtilForEachProcessorDpc(PKDEFERRED_ROUTINE deferred_routine, void *context) {
448  const auto number_of_processors =
449  KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
450  for (ULONG processor_index = 0; processor_index < number_of_processors;
451  processor_index++) {
452  PROCESSOR_NUMBER processor_number = {};
453  auto status =
454  KeGetProcessorNumberFromIndex(processor_index, &processor_number);
455  if (!NT_SUCCESS(status)) {
456  return status;
457  }
458 
459  const auto dpc = reinterpret_cast<PRKDPC>(ExAllocatePoolWithTag(
460  NonPagedPool, sizeof(KDPC), kHyperPlatformCommonPoolTag));
461  if (!dpc) {
462  return STATUS_MEMORY_NOT_ALLOCATED;
463  }
464  KeInitializeDpc(dpc, deferred_routine, context);
465  KeSetImportanceDpc(dpc, HighImportance);
466  status = KeSetTargetProcessorDpcEx(dpc, &processor_number);
467  if (!NT_SUCCESS(status)) {
468  ExFreePoolWithTag(dpc, kHyperPlatformCommonPoolTag);
469  return status;
470  }
471  KeInsertQueueDpc(dpc, nullptr, nullptr);
472  }
473  return STATUS_SUCCESS;
474 }
475 
476 // Sleep the current thread's execution for Millisecond milliseconds.
477 _Use_decl_annotations_ NTSTATUS UtilSleep(LONG Millisecond) {
478  PAGED_CODE();
479 
480  LARGE_INTEGER interval = {};
481  interval.QuadPart = -(10000 * Millisecond); // msec
482  return KeDelayExecutionThread(KernelMode, FALSE, &interval);
483 }
484 
485 // memmem().
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) {
490  return nullptr;
491  }
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]);
496  }
497  }
498  return nullptr;
499 }
500 
501 // A wrapper of MmGetSystemRoutineAddress
502 _Use_decl_annotations_ void *UtilGetSystemProcAddress(
503  const wchar_t *proc_name) {
504  PAGED_CODE();
505 
506  UNICODE_STRING proc_name_U = {};
507  RtlInitUnicodeString(&proc_name_U, proc_name);
508  return MmGetSystemRoutineAddress(&proc_name_U);
509 }
510 
511 // Returns true when a system is on the x86 PAE mode
512 /*_Use_decl_annotations_*/ bool UtilIsX86Pae() {
513  return (!IsX64() && Cr4{__readcr4()}.fields.pae);
514 }
515 
516 // Return true if the given address is accessible.
517 _Use_decl_annotations_ bool UtilIsAccessibleAddress(void *address) {
518  if (!UtilpIsCanonicalFormAddress(address)) {
519  return false;
520  }
521 
522  if (IsX64()) {
523  const auto pxe = UtilpAddressToPxe(address);
524  const auto ppe = UtilpAddressToPpe(address);
525  if (!pxe->valid || !ppe->valid) {
526  return false;
527  }
528  }
529 
530  const auto pde = UtilpAddressToPde(address);
531  const auto pte = UtilpAddressToPte(address);
532  if (!pde->valid) {
533  return false;
534  }
535  if (pde->large_page) {
536  return true; // A large page is always memory resident
537  }
538  if (!pte || !pte->valid) {
539  return false;
540  }
541  return true;
542 }
543 
544 // Checks whether the address is the canonical address
545 _Use_decl_annotations_ static bool UtilpIsCanonicalFormAddress(void *address) {
546  if (!IsX64()) {
547  return true;
548  }
549  return !UtilIsInBounds(0x0000800000000000ull, 0xffff7fffffffffffull,
550  reinterpret_cast<ULONG64>(address));
551 }
552 
553 // Return an address of PXE
554 _Use_decl_annotations_ static HardwarePte *UtilpAddressToPxe(
555  const void *address) {
556  const auto addr = reinterpret_cast<ULONG_PTR>(address);
557  const auto pxe_index = (addr >> g_utilp_pxi_shift) & g_utilp_pxi_mask;
558  const auto offset = pxe_index * sizeof(HardwarePte);
559  return reinterpret_cast<HardwarePte *>(g_utilp_pxe_base + offset);
560 }
561 
562 // Return an address of PPE
563 _Use_decl_annotations_ static HardwarePte *UtilpAddressToPpe(
564  const void *address) {
565  const auto addr = reinterpret_cast<ULONG_PTR>(address);
566  const auto ppe_index = (addr >> g_utilp_ppi_shift) & g_utilp_ppi_mask;
567  const auto offset = ppe_index * sizeof(HardwarePte);
568  return reinterpret_cast<HardwarePte *>(g_utilp_ppe_base + offset);
569 }
570 
571 // Return an address of PDE
572 _Use_decl_annotations_ static HardwarePte *UtilpAddressToPde(
573  const void *address) {
574  const auto addr = reinterpret_cast<ULONG_PTR>(address);
575  const auto pde_index = (addr >> g_utilp_pdi_shift) & g_utilp_pdi_mask;
576  const auto offset = pde_index * sizeof(HardwarePte);
577  return reinterpret_cast<HardwarePte *>(g_utilp_pde_base + offset);
578 }
579 
580 // Return an address of PTE
581 _Use_decl_annotations_ static HardwarePte *UtilpAddressToPte(
582  const void *address) {
583  const auto addr = reinterpret_cast<ULONG_PTR>(address);
584  const auto pte_index = (addr >> g_utilp_pti_shift) & g_utilp_pti_mask;
585  const auto offset = pte_index * sizeof(HardwarePte);
586  return reinterpret_cast<HardwarePte *>(g_utilp_pte_base + offset);
587 }
588 
589 // VA -> PA
590 _Use_decl_annotations_ ULONG64 UtilPaFromVa(void *va) {
591  const auto pa = MmGetPhysicalAddress(va);
592  return pa.QuadPart;
593 }
594 
595 // VA -> PFN
596 _Use_decl_annotations_ PFN_NUMBER UtilPfnFromVa(void *va) {
597  return UtilPfnFromPa(UtilPaFromVa(va));
598 }
599 
600 // PA -> PFN
601 _Use_decl_annotations_ PFN_NUMBER UtilPfnFromPa(ULONG64 pa) {
602  return static_cast<PFN_NUMBER>(pa >> PAGE_SHIFT);
603 }
604 
605 // PA -> VA
606 _Use_decl_annotations_ void *UtilVaFromPa(ULONG64 pa) {
607  PHYSICAL_ADDRESS pa2 = {};
608  pa2.QuadPart = pa;
609  return MmGetVirtualForPhysical(pa2);
610 }
611 
612 // PNF -> PA
613 _Use_decl_annotations_ ULONG64 UtilPaFromPfn(PFN_NUMBER pfn) {
614  return static_cast<ULONG64>(pfn) << PAGE_SHIFT;
615 }
616 
617 // PFN -> VA
618 _Use_decl_annotations_ void *UtilVaFromPfn(PFN_NUMBER pfn) {
619  return UtilVaFromPa(UtilPaFromPfn(pfn));
620 }
621 
622 // Allocates continuous physical memory
623 _Use_decl_annotations_ void *UtilAllocateContiguousMemory(
624  SIZE_T number_of_bytes) {
625  PHYSICAL_ADDRESS highest_acceptable_address = {};
626  highest_acceptable_address.QuadPart = -1;
628  // Allocate NX physical memory
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);
634  } else {
635 #pragma warning(push)
636 #pragma warning(disable : 30029)
637  return MmAllocateContiguousMemory(number_of_bytes,
638  highest_acceptable_address);
639 #pragma warning(pop)
640  }
641 }
642 
643 // Frees an address allocated by UtilAllocateContiguousMemory()
644 _Use_decl_annotations_ void UtilFreeContiguousMemory(void *base_address) {
645  MmFreeContiguousMemory(base_address);
646 }
647 
648 // Executes VMCALL
649 _Use_decl_annotations_ NTSTATUS UtilVmCall(HypercallNumber hypercall_number,
650  void *context) {
651  __try {
652  const auto vmx_status = static_cast<VmxStatus>(
653  AsmVmxCall(static_cast<ULONG>(hypercall_number), context));
654  return (vmx_status == VmxStatus::kOk) ? STATUS_SUCCESS
655  : STATUS_UNSUCCESSFUL;
656 
657 #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "Catch all.");
658  } __except (EXCEPTION_EXECUTE_HANDLER) {
659  const auto status = GetExceptionCode();
661  HYPERPLATFORM_LOG_WARN_SAFE("Exception thrown (code %08x)", status);
662  return status;
663  }
664 }
665 
666 // Debug prints registers
667 _Use_decl_annotations_ void UtilDumpGpRegisters(const AllRegisters *all_regs,
668  ULONG_PTR stack_pointer) {
669  const auto current_irql = KeGetCurrentIrql();
670  if (current_irql < DISPATCH_LEVEL) {
671  KeRaiseIrqlToDpcLevel();
672  }
673 
674 #if defined(_AMD64_)
676  "Context at %p: "
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,
687  all_regs->gp.r15, all_regs->flags.all);
688 #else
690  "Context at %p: "
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,
696  all_regs->gp.bp, all_regs->flags.all);
697 #endif
698 
699  if (current_irql < DISPATCH_LEVEL) {
700  KeLowerIrql(current_irql);
701  }
702 }
703 
704 // Reads natural-width VMCS
705 _Use_decl_annotations_ ULONG_PTR UtilVmRead(VmcsField field) {
706  size_t field_value = 0;
707  const auto vmx_status = static_cast<VmxStatus>(
708  __vmx_vmread(static_cast<size_t>(field), &field_value));
709  if (vmx_status != VmxStatus::kOk) {
712  static_cast<ULONG_PTR>(vmx_status), static_cast<ULONG_PTR>(field), 0);
713  }
714  return field_value;
715 }
716 
717 // Reads 64bit-width VMCS
718 _Use_decl_annotations_ ULONG64 UtilVmRead64(VmcsField field) {
719 #if defined(_AMD64_)
720  return UtilVmRead(field);
721 #else
722  // Only 64bit fields should be given on x86 because it access field + 1 too.
723  // Also, the field must be even number.
724  NT_ASSERT(UtilIsInBounds(field, VmcsField::kIoBitmapA,
726  NT_ASSERT((static_cast<ULONG>(field) % 2) == 0);
727 
728  ULARGE_INTEGER value64 = {};
729  value64.LowPart = UtilVmRead(field);
730  value64.HighPart =
731  UtilVmRead(static_cast<VmcsField>(static_cast<ULONG>(field) + 1));
732  return value64.QuadPart;
733 #endif
734 }
735 
736 // Writes natural-width VMCS
737 _Use_decl_annotations_ VmxStatus UtilVmWrite(VmcsField field,
738  ULONG_PTR field_value) {
739  return static_cast<VmxStatus>(
740  __vmx_vmwrite(static_cast<size_t>(field), field_value));
741 }
742 
743 // Writes 64bit-width VMCS
744 _Use_decl_annotations_ VmxStatus UtilVmWrite64(VmcsField field,
745  ULONG64 field_value) {
746 #if defined(_AMD64_)
747  return UtilVmWrite(field, field_value);
748 #else
749  // Only 64bit fields should be given on x86 because it access field + 1 too.
750  // Also, the field must be even number.
751  NT_ASSERT(UtilIsInBounds(field, VmcsField::kIoBitmapA,
753  NT_ASSERT((static_cast<ULONG>(field) % 2) == 0);
754 
755  ULARGE_INTEGER value64 = {};
756  value64.QuadPart = field_value;
757  const auto vmx_status = UtilVmWrite(field, value64.LowPart);
758  if (vmx_status != VmxStatus::kOk) {
759  return vmx_status;
760  }
761  return UtilVmWrite(static_cast<VmcsField>(static_cast<ULONG>(field) + 1),
762  value64.HighPart);
763 #endif
764 }
765 
766 // Reads natural-width MSR
767 _Use_decl_annotations_ ULONG_PTR UtilReadMsr(Msr msr) {
768  return static_cast<ULONG_PTR>(__readmsr(static_cast<unsigned long>(msr)));
769 }
770 
771 // Reads 64bit-width MSR
772 _Use_decl_annotations_ ULONG64 UtilReadMsr64(Msr msr) {
773  return __readmsr(static_cast<unsigned long>(msr));
774 }
775 
776 // Writes natural-width MSR
777 _Use_decl_annotations_ void UtilWriteMsr(Msr msr, ULONG_PTR value) {
778  __writemsr(static_cast<unsigned long>(msr), value);
779 }
780 
781 // Writes 64bit-width MSR
782 _Use_decl_annotations_ void UtilWriteMsr64(Msr msr, ULONG64 value) {
783  __writemsr(static_cast<unsigned long>(msr), value);
784 }
785 
786 // Executes the INVEPT instruction and invalidates EPT entry cache
787 /*_Use_decl_annotations_*/ VmxStatus UtilInveptGlobal() {
788  InvEptDescriptor desc = {};
789  return static_cast<VmxStatus>(
791 }
792 
793 // Executes the INVVPID instruction (type 0)
794 _Use_decl_annotations_ VmxStatus UtilInvvpidIndividualAddress(USHORT vpid,
795  void *address) {
796  InvVpidDescriptor desc = {};
797  desc.vpid = vpid;
798  desc.linear_address = reinterpret_cast<ULONG64>(address);
799  return static_cast<VmxStatus>(
801 }
802 
803 // Executes the INVVPID instruction (type 1)
804 _Use_decl_annotations_ VmxStatus UtilInvvpidSingleContext(USHORT vpid) {
805  InvVpidDescriptor desc = {};
806  desc.vpid = vpid;
807  return static_cast<VmxStatus>(
809 }
810 
811 // Executes the INVVPID instruction (type 2)
812 /*_Use_decl_annotations_*/ VmxStatus UtilInvvpidAllContext() {
813  InvVpidDescriptor desc = {};
814  return static_cast<VmxStatus>(
816 }
817 
818 // Executes the INVVPID instruction (type 3)
819 _Use_decl_annotations_ VmxStatus
821  InvVpidDescriptor desc = {};
822  desc.vpid = vpid;
823  return static_cast<VmxStatus>(
825 }
826 
827 // Loads the PDPTE registers from CR3 to VMCS
828 _Use_decl_annotations_ void UtilLoadPdptes(ULONG_PTR cr3_value) {
829  const auto current_cr3 = __readcr3();
830 
831  // Have to load cr3 to make UtilPfnFromVa() work properly.
832  __writecr3(cr3_value);
833 
834  // Gets PDPTEs form CR3
835  PdptrRegister pd_pointers[4] = {};
836  for (auto i = 0ul; i < 4; ++i) {
837  const auto pd_addr = g_utilp_pde_base + i * PAGE_SIZE;
838  pd_pointers[i].fields.present = true;
839  pd_pointers[i].fields.page_directory_pa =
840  UtilPfnFromVa(reinterpret_cast<void *>(pd_addr));
841  }
842 
843  __writecr3(current_cr3);
844  UtilVmWrite64(VmcsField::kGuestPdptr0, pd_pointers[0].all);
845  UtilVmWrite64(VmcsField::kGuestPdptr1, pd_pointers[1].all);
846  UtilVmWrite64(VmcsField::kGuestPdptr2, pd_pointers[2].all);
847  UtilVmWrite64(VmcsField::kGuestPdptr3, pd_pointers[3].all);
848 }
849 
850 // Does RtlCopyMemory safely even if destination is a read only region
851 _Use_decl_annotations_ NTSTATUS UtilForceCopyMemory(void *destination,
852  const void *source,
853  SIZE_T length) {
854  auto mdl = IoAllocateMdl(destination, static_cast<ULONG>(length), FALSE,
855  FALSE, nullptr);
856  if (!mdl) {
857  return STATUS_INSUFFICIENT_RESOURCES;
858  }
859  MmBuildMdlForNonPagedPool(mdl);
860 
861 #pragma warning(push)
862 #pragma warning(disable : 28145)
863  // Following MmMapLockedPagesSpecifyCache() call causes bug check in case
864  // you are using Driver Verifier. The reason is explained as followings:
865  //
866  // A driver must not try to create more than one system-address-space
867  // mapping for an MDL. Additionally, because an MDL that is built by the
868  // MmBuildMdlForNonPagedPool routine is already mapped to the system
869  // address space, a driver must not try to map this MDL into the system
870  // address space again by using the MmMapLockedPagesSpecifyCache routine.
871  // -- MSDN
872  //
873  // This flag modification hacks Driver Verifier's check and prevent leading
874  // bug check.
875  mdl->MdlFlags &= ~MDL_SOURCE_IS_NONPAGED_POOL;
876  mdl->MdlFlags |= MDL_PAGES_LOCKED;
877 #pragma warning(pop)
878 
879  const auto writable_dest =
880  MmMapLockedPagesSpecifyCache(mdl, KernelMode, MmCached, nullptr, FALSE,
881  NormalPagePriority | MdlMappingNoExecute);
882  if (!writable_dest) {
883  IoFreeMdl(mdl);
884  return STATUS_INSUFFICIENT_RESOURCES;
885  }
886  RtlCopyMemory(writable_dest, source, length);
887  MmUnmapLockedPages(writable_dest, mdl);
888  IoFreeMdl(mdl);
889  return STATUS_SUCCESS;
890 }
891 
892 } // extern "C"
static ULONG_PTR g_utilp_pxi_mask
Definition: util.cpp:130
static MmAllocateContiguousNodeMemoryType * g_utilp_MmAllocateContiguousNodeMemory
Definition: util.cpp:118
HypercallNumber
Available command numbers for VMCALL.
Definition: util.h:68
ULONG64 UtilPaFromPfn(PFN_NUMBER pfn)
Definition: util.cpp:613
static HardwarePte * UtilpAddressToPde(_In_ const void *address)
#define HYPERPLATFORM_LOG_DEBUG(format,...)
Logs a message as respective severity.
Definition: log.h:34
static ULONG_PTR g_utilp_pti_shift
Definition: util.cpp:128
VmxStatus UtilVmWrite(VmcsField field, ULONG_PTR field_value)
Definition: util.cpp:737
NTKERNELAPI _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS HighestAcceptableAddress
Definition: util.cpp:44
ULONG_PTR ax
Definition: ia32_type.h:100
VmxStatus
Indicates a result of VMX-instructions.
Definition: util.h:55
static NTSTATUS UtilpInitializePhysicalMemoryRanges()
Definition: util.cpp:323
void * dll_base
Definition: util.cpp:57
unsigned pae
[5] Physical Address Extension
Definition: ia32_type.h:152
void * entry_point
Definition: util.cpp:58
PFN_NUMBER UtilPfnFromVa(void *va)
Definition: util.cpp:596
static ULONG_PTR g_utilp_pdi_shift
Definition: util.cpp:127
static const auto kUtilpPtiMaskPae
bool UtilIsAccessibleAddress(void *address)
Definition: util.cpp:517
FlagRegister flags
Definition: ia32_type.h:113
#define HYPERPLATFORM_COMMON_BUG_CHECK(hp_bug_check_code, param1, param2, param3)
Issues a bug check.
Definition: common.h:69
static const ULONG kHyperPlatformCommonPoolTag
A pool tag.
Definition: common.h:93
constexpr bool IsX64()
Checks if a system is x64.
Definition: common.h:128
static ULONG_PTR g_utilp_pti_mask
Definition: util.cpp:133
#define HYPERPLATFORM_COMMON_DBG_BREAK()
Sets a break point that works only when a debugger is present.
Definition: common.h:55
NTKERNELAPI _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS _In_opt_ PHYSICAL_ADDRESS BoundaryAddressMultiple
Definition: util.cpp:44
NTKERNELAPI _In_ PHYSICAL_ADDRESS LowestAcceptableAddress
Definition: util.cpp:44
void * UtilVaFromPa(ULONG64 pa)
Definition: util.cpp:606
LIST_ENTRY in_initialization_order_links
Definition: util.cpp:56
const PhysicalMemoryDescriptor * UtilGetPhysicalMemoryRanges()
Returns ranges of physical memory on the system.
Definition: util.cpp:403
ULONG64 present
[0]
Definition: ia32_type.h:482
See: CONTROL REGISTERS.
Definition: ia32_type.h:144
NTKERNELAPI _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS _In_opt_ PHYSICAL_ADDRESS _In_ ULONG Protect
Definition: util.cpp:44
static PVOID NTAPI UtilpUnsafePcToFileHeader(_In_ PVOID pc_value, _Out_ PVOID *base_of_image)
static const auto kUtilpUseRtlPcToFileHeader
Definition: util.cpp:28
static HardwarePte * UtilpAddressToPte(_In_ const void *address)
Operation succeeded.
static bool UtilpIsCanonicalFormAddress(_In_ void *address)
static RtlPcToFileHeaderType * g_utilp_RtlPcToFileHeader
Definition: util.cpp:111
ULONG64 linear_address
Definition: ia32_type.h:1607
NTKERNELAPI PVOID NTAPI RtlPcToFileHeader(_In_ PVOID PcValue, _Out_ PVOID *BaseOfImage)
NTSTATUS UtilForEachProcessorDpc(PKDEFERRED_ROUTINE deferred_routine, void *context)
Definition: util.cpp:447
void UtilWriteMsr(Msr msr, ULONG_PTR value)
Definition: util.cpp:777
void * UtilAllocateContiguousMemory(SIZE_T number_of_bytes)
Definition: util.cpp:623
ULONG64 UtilVmRead64(VmcsField field)
Definition: util.cpp:718
Represents a physical memory ranges of the system.
Definition: util.h:41
void UtilTermination()
Frees all resources allocated for the sake of the Util functions.
Definition: util.cpp:170
void * UtilMemMem(const void *search_base, SIZE_T search_size, const void *pattern, SIZE_T pattern_size)
Definition: util.cpp:486
void * UtilVaFromPfn(PFN_NUMBER pfn)
Definition: util.cpp:618
ULONG_PTR di
Definition: ia32_type.h:93
static ULONG_PTR g_utilp_pte_base
Definition: util.cpp:123
VmxStatus UtilInvvpidIndividualAddress(USHORT vpid, void *address)
Definition: util.cpp:794
VmxStatus UtilInveptGlobal()
Executes the INVEPT instruction and invalidates EPT entry cache.
Definition: util.cpp:787
VmxStatus UtilInvvpidSingleContextExceptGlobal(USHORT vpid)
Definition: util.cpp:820
Defines page table related constants.
static const auto kUtilpPdiShiftPae
ULONG_PTR all
Definition: ia32_type.h:43
void * UtilGetSystemProcAddress(const wchar_t *proc_name)
Definition: util.cpp:502
ULONG_PTR dx
Definition: ia32_type.h:98
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
Definition: util.cpp:120
NTSTATUS UtilVmCall(HypercallNumber hypercall_number, void *context)
Definition: util.cpp:649
void UtilWriteMsr64(Msr msr, ULONG64 value)
Definition: util.cpp:782
void UtilDumpGpRegisters(const AllRegisters *all_regs, ULONG_PTR stack_pointer)
Definition: util.cpp:667
static NTSTATUS UtilpInitializeRtlPcToFileHeader(_In_ PDRIVER_OBJECT driver_object)
Definition: util.cpp:53
static ULONG_PTR g_utilp_pxi_shift
Definition: util.cpp:125
Declares interfaces to assembly functions.
static const auto kUtilpPdiMaskPae
void * UtilPcToFileHeader(void *pc_value)
Definition: util.cpp:317
ULONG_PTR bx
Definition: ia32_type.h:97
GpRegisters gp
Definition: ia32_type.h:112
Msr
See: MODEL-SPECIFIC REGISTERS (MSRS)
Definition: ia32_type.h:576
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)
Definition: util.cpp:590
ULONG_PTR UtilReadMsr(Msr msr)
Definition: util.cpp:767
See: INVEPT Descriptor.
Definition: ia32_type.h:1590
VmcsField
See: FIELD ENCODING IN VMCS.
Definition: ia32_type.h:648
UNICODE_STRING full_dll_name
Definition: util.cpp:60
VmxStatus UtilInvvpidSingleContext(USHORT vpid)
Definition: util.cpp:804
static const auto kUtilpPteBasePae
Represents ranges of addresses.
Definition: util.h:30
ULONG64 page_directory_pa
[12:52]
Definition: ia32_type.h:488
static ULONG_PTR g_utilp_pde_base
Definition: util.cpp:122
#define HYPERPLATFORM_LOG_WARN_SAFE(format,...)
Definition: log.h:67
void UtilLoadPdptes(ULONG_PTR cr3_value)
Definition: util.cpp:828
NTSTATUS UtilSleep(LONG Millisecond)
Definition: util.cpp:477
#define HYPERPLATFORM_LOG_DEBUG_SAFE(format,...)
Buffers a message as respective severity.
Definition: log.h:57
static HardwarePte * UtilpAddressToPpe(_In_ const void *address)
See: PDPTE Registers.
Definition: ia32_type.h:479
ULONG_PTR si
Definition: ia32_type.h:94
LIST_ENTRY in_memory_order_links
Definition: util.cpp:55
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)
Definition: util.cpp:812
struct PdptrRegister::@12 fields
ULONG_PTR UtilVmRead(VmcsField field)
Definition: util.cpp:705
bool UtilIsX86Pae()
Checks if the system is a PAE-enabled x86 system.
Definition: util.cpp:512
NTKERNELAPI _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS _In_opt_ PHYSICAL_ADDRESS _In_ ULONG _In_ NODE_REQUIREMENT PreferredNode
Definition: util.cpp:44
NTSTATUS UtilForceCopyMemory(void *destination, const void *source, SIZE_T length)
Definition: util.cpp:851
static ULONG_PTR g_utilp_pdi_mask
Definition: util.cpp:132
static PhysicalMemoryDescriptor * g_utilp_physical_memory_ranges
Definition: util.cpp:115
void UtilFreeContiguousMemory(void *base_address)
Definition: util.cpp:644
static ULONG_PTR g_utilp_ppi_shift
Definition: util.cpp:126
static ULONG_PTR g_utilp_ppe_base
Definition: util.cpp:121
ULONG_PTR bp
Definition: ia32_type.h:95
Declares and implements common things across the project.
static const auto kUtilpPtiShiftPae
decltype(MmAllocateContiguousNodeMemory) MmAllocateContiguousNodeMemoryType
Definition: util.cpp:50
LIST_ENTRY in_load_order_links
Definition: util.cpp:54
static PhysicalMemoryDescriptor * UtilpBuildPhysicalMemoryRanges()
Definition: util.cpp:350
ULONG64 UtilReadMsr64(Msr msr)
Definition: util.cpp:772
NTSTATUS UtilInitialization(PDRIVER_OBJECT driver_object)
Definition: util.cpp:142
See: INVVPID Descriptor.
Definition: ia32_type.h:1603
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
Definition: util.cpp:113
ULONG_PTR cx
Definition: ia32_type.h:99
constexpr bool UtilIsInBounds(_In_ const T &value, _In_ const T &min, _In_ const T &max)
Tests if value is in between min and max.
Definition: util.h:300
PFN_NUMBER UtilPfnFromPa(ULONG64 pa)
Definition: util.cpp:601
decltype(RtlPcToFileHeader) RtlPcToFileHeaderType
Definition: util.cpp:38
static ULONG_PTR g_utilp_ppi_mask
Definition: util.cpp:131
ULONG size_of_image
Definition: util.cpp:59
NTSTATUS UtilForEachProcessor(NTSTATUS(*callback_routine)(void *), void *context)
Definition: util.cpp:412
Represents a stack layout after a sequence of PUSHFx, PUSHAx.
Definition: ia32_type.h:111
struct Cr4::@3 fields
VmxStatus UtilVmWrite64(VmcsField field, ULONG64 field_value)
Definition: util.cpp:744