Esempio n. 1
0
// RDMSR and WRMSR
_Use_decl_annotations_ static void VmmpHandleMsrAccess(
    GuestContext *guest_context, bool read_access) {
  // Apply it for VMCS instead of a real MSR if a speficied MSR is either of
  // them.
  const auto msr = static_cast<Msr>(guest_context->gp_regs->cx);

  bool transfer_to_vmcs = false;
  VmcsField vmcs_field = {};
  switch (msr) {
    case Msr::kIa32SysenterCs:
      vmcs_field = VmcsField::kGuestSysenterCs;
      transfer_to_vmcs = true;
      break;
    case Msr::kIa32SysenterEsp:
      vmcs_field = VmcsField::kGuestSysenterEsp;
      transfer_to_vmcs = true;
      break;
    case Msr::kIa32SysenterEip:
      vmcs_field = VmcsField::kGuestSysenterEip;
      transfer_to_vmcs = true;
      break;
    case Msr::kIa32GsBase:
      vmcs_field = VmcsField::kGuestGsBase;
      transfer_to_vmcs = true;
      break;
    case Msr::kIa32FsBase:
      vmcs_field = VmcsField::kGuestFsBase;
      break;
    default:
      break;
  }
  // Do not shadow 64bit fields because the current implmentation for x86 is not
  // able to handle it due to a simple use of UtilVmWrite() below.
  NT_ASSERT(UtilIsInBounds(vmcs_field, VmcsField::kIoBitmapA,
                           VmcsField::kHostIa32PerfGlobalCtrlHigh) == false);

  // This unconditional __readmsr and __writemsr may cause #GP resulting in
  // bug check. A proper way to solve this is check supported MSR values
  // beforehand and inject an exception when unsupported MSR values are given.
  LARGE_INTEGER msr_value = {};
  if (read_access) {
    if (transfer_to_vmcs) {
      msr_value.QuadPart = UtilVmRead(vmcs_field);
    } else {
      msr_value.QuadPart = UtilReadMsr64(msr);
    }
    guest_context->gp_regs->ax = msr_value.LowPart;
    guest_context->gp_regs->dx = msr_value.HighPart;
  } else {
    msr_value.LowPart = static_cast<ULONG>(guest_context->gp_regs->ax);
    msr_value.HighPart = static_cast<ULONG>(guest_context->gp_regs->dx);
    if (transfer_to_vmcs) {
      UtilVmWrite(vmcs_field, static_cast<ULONG_PTR>(msr_value.QuadPart));
    } else {
      UtilWriteMsr64(msr, msr_value.QuadPart);
    }
  }

  VmmpAdjustGuestInstructionPointer(guest_context->ip);
}
Esempio n. 2
0
// Returns a memory type based on MTRRs
_Use_decl_annotations_ static memory_type EptpGetMemoryType(
	ULONG64 physical_address) {
	// Indicate that MTRR is not defined (as a default)
	UCHAR result_type = MAXUCHAR;

	// Looks for MTRR that includes the specified physical_address
	for (const auto mtrr_entry : g_eptp_mtrr_entries) {
		if (!mtrr_entry.enabled) {
			// Reached out the end of stored MTRRs
			break;
		}

		if (!UtilIsInBounds(physical_address, mtrr_entry.range_base,
			mtrr_entry.range_end)) {
			// This MTRR does not describe a memory type of the physical_address
			continue;
		}

		// See: MTRR Precedences
		if (mtrr_entry.fixedMtrr) {
			// If a fixed MTRR describes a memory type, it is priority
			result_type = mtrr_entry.type;
			break;
		}

		if (mtrr_entry.type == static_cast<UCHAR>(memory_type::kUncacheable)) {
			// If a memory type is UC, it is priority. Do not continue to search as
			// UC has the highest priority
			result_type = mtrr_entry.type;
			break;
		}

		if (result_type == static_cast<UCHAR>(memory_type::kWriteThrough) ||
			mtrr_entry.type == static_cast<UCHAR>(memory_type::kWriteThrough)) {
			if (result_type == static_cast<UCHAR>(memory_type::kWriteBack)) {
				// If two or more MTRRs describes an over-wrapped memory region, and
				// one is WT and the other one is WB, use WT. However, look for other
				// MTRRs, as the other MTRR specifies the memory address as UC, which is
				// priority.
				result_type = static_cast<UCHAR>(memory_type::kWriteThrough);
				continue;
			}
		}

		// Otherwise, processor behavior is undefined. We just use the last MTRR
		// describes the memory address.
		result_type = mtrr_entry.type;
	}

	// Use the default MTRR if no MTRR entry is found
	if (result_type == MAXUCHAR) {
		result_type = g_eptp_mtrr_default_type;
	}

	return static_cast<memory_type>(result_type);
}
Esempio n. 3
0
// Checks if the export is listed as a hook target, and if so install a hook.
_Use_decl_annotations_ EXTERN_C static bool DdimonpEnumExportedSymbolsCallback(
    ULONG index, ULONG_PTR base_address, PIMAGE_EXPORT_DIRECTORY directory,
    ULONG_PTR directory_base, ULONG_PTR directory_end, void* context) {
  PAGED_CODE();

  if (!context) {
    return false;
  }

  auto functions =
      reinterpret_cast<ULONG*>(base_address + directory->AddressOfFunctions);
  auto ordinals = reinterpret_cast<USHORT*>(base_address +
                                            directory->AddressOfNameOrdinals);
  auto names =
      reinterpret_cast<ULONG*>(base_address + directory->AddressOfNames);

  auto ord = ordinals[index];
  auto export_address = base_address + functions[ord];
  auto export_name = reinterpret_cast<const char*>(base_address + names[index]);

  // Check if an export is forwared one? If so, ignore it.
  if (UtilIsInBounds(export_address, directory_base, directory_end)) {
    return true;
  }

  // convert the name to UNICODE_STRING
  wchar_t name[100];
  auto status =
      RtlStringCchPrintfW(name, RTL_NUMBER_OF(name), L"%S", export_name);
  if (!NT_SUCCESS(status)) {
    return true;
  }
  UNICODE_STRING name_u = {};
  RtlInitUnicodeString(&name_u, name);

  for (auto& target : g_ddimonp_hook_targets) {
    // Is this export listed as a target
    if (!FsRtlIsNameInExpression(&target.target_name, &name_u, TRUE, nullptr)) {
      continue;
    }

    // Yes, install a hook to the export
    if (!ShInstallHook(reinterpret_cast<SharedShadowHookData*>(context),
                       reinterpret_cast<void*>(export_address), &target)) {
      // This is an error which should not happen
      DdimonpFreeAllocatedTrampolineRegions();
      return false;
    }
    HYPERPLATFORM_LOG_INFO("Hook has been installed at %p %s.", export_address,
                           export_name);
  }
  return true;
}
Esempio n. 4
0
// Returns if the physical_address is device memory (which could not have a
// corresponding PFN entry)
_Use_decl_annotations_ static bool EptpIsDeviceMemory(
    ULONG64 physical_address) {
  const auto pm_ranges = UtilGetPhysicalMemoryRanges();
  for (auto i = 0ul; i < pm_ranges->number_of_runs; ++i) {
    const auto current_run = &pm_ranges->run[i];
    const auto base_addr =
        static_cast<ULONG64>(current_run->base_page) * PAGE_SIZE;
    const auto endAddr = base_addr + current_run->page_count * PAGE_SIZE - 1;
    if (UtilIsInBounds(physical_address, base_addr, endAddr)) {
      return false;
    }
  }
  return true;
}
Esempio n. 5
0
// A fake RtlPcToFileHeader without accquireing PsLoadedModuleSpinLock. Thus, it
// is unsafe and should be updated if we can locate PsLoadedModuleSpinLock.
_Use_decl_annotations_ static PVOID NTAPI
MmonpUnsafePcToFileHeader(PVOID pc_value, PVOID *base_of_image) {
  if (pc_value < MmSystemRangeStart) {
    return nullptr;
  }

  const auto head = g_mmonp_PsLoadedModuleList;
  for (auto current = head->Flink; current != head; current = current->Flink) {
    const auto module =
        CONTAINING_RECORD(current, LdrDataTableEntry, in_load_order_links);
    const auto driver_end = reinterpret_cast<void *>(
        reinterpret_cast<ULONG_PTR>(module->dll_base) + module->size_of_image);
    if (UtilIsInBounds(pc_value, module->dll_base, driver_end)) {
      *base_of_image = module->dll_base;
      return module->dll_base;
    }
  }
  return nullptr;
}