// Power callback routine dealing with hibernate and sleep
_Use_decl_annotations_ static void PowerCallbackpCallbackRoutine(
    PVOID callback_context, PVOID argument1, PVOID argument2) {
  UNREFERENCED_PARAMETER(callback_context);
  PAGED_CODE();

  if (argument1 != reinterpret_cast<void*>(PO_CB_SYSTEM_STATE_LOCK)) {
    return;
  }

  HYPERPLATFORM_COMMON_DBG_BREAK();

  if (argument2) {
    // the computer has just reentered S0.
    HYPERPLATFORM_LOG_INFO("Resuming the system...");
    auto status = VmInitialization();
    if (!NT_SUCCESS(status)) {
      HYPERPLATFORM_LOG_ERROR(
          "Failed to re-virtualize processors. Please unload the driver.");
    }
  } else {
    // the computer is about to exit system power state S0
    HYPERPLATFORM_LOG_INFO("Suspending the system...");
    VmTermination();
  }
}
Beispiel #2
0
// Virtualize the current processor
_Use_decl_annotations_ static NTSTATUS VmpStartVM(void *context) {
  HYPERPLATFORM_LOG_INFO("Initializing VMX for the processor %d.",
                         KeGetCurrentProcessorNumberEx(nullptr));
  const auto ok = AsmInitializeVm(VmpInitializeVm, context);
  NT_ASSERT(VmpIsVmmInstalled() == ok);
  if (!ok) {
    return STATUS_UNSUCCESSFUL;
  }
  HYPERPLATFORM_LOG_INFO("Initialized successfully.");
  return STATUS_SUCCESS;
}
Beispiel #3
0
// A driver entry point
_Use_decl_annotations_ NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object,
                                            PUNICODE_STRING registry_path) {
  UNREFERENCED_PARAMETER(registry_path);
  PAGED_CODE();

  static const wchar_t kLogFilePath[] = L"\\SystemRoot\\HyperPlatform.log";
  static const auto kLogLevel =
      (IsReleaseBuild()) ? kLogPutLevelInfo | kLogOptDisableFunctionName
                         : kLogPutLevelDebug | kLogOptDisableFunctionName;

  auto status = STATUS_UNSUCCESSFUL;
  driver_object->DriverUnload = DriverpDriverUnload;
  HYPERPLATFORM_COMMON_DBG_BREAK();

  // Initialize log functions
  bool need_reinitialization = false;
  status = LogInitialization(kLogLevel, kLogFilePath);
  if (status == STATUS_REINITIALIZATION_NEEDED) {
    need_reinitialization = true;
  } else if (!NT_SUCCESS(status)) {
    return status;
  }

  // Test if the system is supported
  if (!DriverpIsSuppoetedOS()) {
    return STATUS_CANCELLED;
  }

  // Initialize perf functions
  status = PerfInitialization();
  if (!NT_SUCCESS(status)) {
    LogTermination();
    return status;
  }

  // Initialize utility functions
  status = UtilInitialization();
  if (!NT_SUCCESS(status)) {
    PerfTermination();
    LogTermination();
    return status;
  }

  // Virtualize all processors
  status = VmInitialization();
  if (!NT_SUCCESS(status)) {
    UtilTermination();
    PerfTermination();
    LogTermination();
    return status;
  }

  // Register re-initialization for the log functions if needed
  if (need_reinitialization) {
    LogRegisterReinitialization(driver_object);
  }

  HYPERPLATFORM_LOG_INFO("The VMM has been installed.");
  return status;
}
Beispiel #4
0
_Use_decl_annotations_ static void PerfpOutputRoutine(
    const char* location_name, ULONG64 total_execution_count,
    ULONG64 total_elapsed_time, void* output_context) {
  UNREFERENCED_PARAMETER(output_context);
  HYPERPLATFORM_LOG_INFO("%-45s,%20I64u,%20I64u,", location_name,
                         total_execution_count, total_elapsed_time);
}
Beispiel #5
0
// Registers LogpReinitializationRoutine() for re-initialization.
_Use_decl_annotations_ void LogRegisterReinitialization(
    PDRIVER_OBJECT driver_object) {
  PAGED_CODE();
  IoRegisterBootDriverReinitialization(
      driver_object, LogpReinitializationRoutine, &g_logp_log_buffer_info);
  HYPERPLATFORM_LOG_INFO("The log file will be activated later.");
}
Beispiel #6
0
// Initializes DdiMon
_Use_decl_annotations_ EXTERN_C NTSTATUS
DdimonInitialization(SharedShadowHookData* shared_sh_data) {
  HYPERPLATFORM_COMMON_DBG_BREAK();

  // Get a base address of ntoskrnl
  auto nt_base = UtilPcToFileHeader(KdDebuggerEnabled);
  if (!nt_base) {
    return STATUS_UNSUCCESSFUL;
  }

  // Install hooks by enumerating exports of ntoskrnl, but not activate them yet
  auto status = DdimonpEnumExportedSymbols(reinterpret_cast<ULONG_PTR>(nt_base),
                                           DdimonpEnumExportedSymbolsCallback,
                                           shared_sh_data);
  if (!NT_SUCCESS(status)) {
    return status;
  }

  // Activate installed hooks
  status = ShEnableHooks();
  if (!NT_SUCCESS(status)) {
    DdimonpFreeAllocatedTrampolineRegions();
    return status;
  }

  HYPERPLATFORM_LOG_INFO("DdiMon has been initialized.");
  return status;
}
Beispiel #7
0
// Initialize a log file related code such as a flushing thread.
_Use_decl_annotations_ static NTSTATUS LogpInitializeBufferInfo(
    const wchar_t *log_file_path, LogBufferInfo *info) {
  PAGED_CODE();
  NT_ASSERT(log_file_path);
  NT_ASSERT(info);

  KeInitializeSpinLock(&info->spin_lock);

  auto status = RtlStringCchCopyW(
      info->log_file_path, RTL_NUMBER_OF_FIELD(LogBufferInfo, log_file_path),
      log_file_path);
  if (!NT_SUCCESS(status)) {
    return status;
  }

  status = ExInitializeResourceLite(&info->resource);
  if (!NT_SUCCESS(status)) {
    return status;
  }
  info->resource_initialized = true;

  // Allocate two log buffers on NonPagedPool.
  info->log_buffer1 = reinterpret_cast<char *>(
      ExAllocatePoolWithTag(NonPagedPoolNx, kLogpBufferSize, kLogpPoolTag));
  if (!info->log_buffer1) {
    LogpFinalizeBufferInfo(info);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  info->log_buffer2 = reinterpret_cast<char *>(
      ExAllocatePoolWithTag(NonPagedPoolNx, kLogpBufferSize, kLogpPoolTag));
  if (!info->log_buffer2) {
    LogpFinalizeBufferInfo(info);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  // Initialize these buffers
  RtlFillMemory(info->log_buffer1, kLogpBufferSize, 0xff);  // for diagnostic
  info->log_buffer1[0] = '\0';
  info->log_buffer1[kLogpBufferSize - 1] = '\0';  // at the end

  RtlFillMemory(info->log_buffer2, kLogpBufferSize, 0xff);  // for diagnostic
  info->log_buffer2[0] = '\0';
  info->log_buffer2[kLogpBufferSize - 1] = '\0';  // at the end

  // Buffer should be used is log_buffer1, and location should be written logs
  // is the head of the buffer.
  info->log_buffer_head = info->log_buffer1;
  info->log_buffer_tail = info->log_buffer1;

  status = LogpInitializeLogFile(info);
  if (status == STATUS_OBJECT_PATH_NOT_FOUND) {
    HYPERPLATFORM_LOG_INFO("The log file needs to be activated later.");
    status = STATUS_REINITIALIZATION_NEEDED;
  } else if (!NT_SUCCESS(status)) {
    LogpFinalizeBufferInfo(info);
  }
  return status;
}
Beispiel #8
0
// Terminates DdiMon
_Use_decl_annotations_ EXTERN_C void DdimonTermination() {
  PAGED_CODE();
  HYPERPLATFORM_COMMON_DBG_BREAK();

  ShDisableHooks();
  UtilSleep(500);
  DdimonpFreeAllocatedTrampolineRegions();
  HYPERPLATFORM_LOG_INFO("DdiMon has been terminated.");
}
Beispiel #9
0
// Terminates the log functions.
_Use_decl_annotations_ void LogTermination() {
  PAGED_CODE();

  HYPERPLATFORM_LOG_DEBUG("Finalizing... (Max log usage = %08x bytes)",
                          g_logp_log_buffer_info.log_max_usage);
  HYPERPLATFORM_LOG_INFO("Bye!");
  g_logp_debug_flag = kLogPutLevelDisable;
  LogpFinalizeBufferInfo(&g_logp_log_buffer_info);
}
Beispiel #10
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;
}
Beispiel #11
0
// Modifies IDTL so that PatchGuard fires soon.
_Use_decl_annotations_ NTSTATUS GMonInstallPatchCallback(void *context) {
  UNREFERENCED_PARAMETER(context);

  Idtr idt = {};
  __sidt(&idt);
  const auto old_limit = idt.limit;
  idt.limit = 0xffff;
  __lidt(&idt);
  __sidt(&idt);
  HYPERPLATFORM_LOG_INFO("Patched IDTL %04hx => %04hx", old_limit, idt.limit);
  return STATUS_SUCCESS;
}
Beispiel #12
0
// Terminates the log functions without releasing resources.
_Use_decl_annotations_ void LogIrpShutdownHandler() {
  PAGED_CODE();

  HYPERPLATFORM_LOG_DEBUG("Flushing... (Max log usage = %08x bytes)",
                          g_logp_log_buffer_info.log_max_usage);
  HYPERPLATFORM_LOG_INFO("Bye!");
  g_logp_debug_flag = kLogPutLevelDisable;

  // Wait until the log buffer is emptied.
  auto &info = g_logp_log_buffer_info;
  while (info.log_buffer_head[0]) {
    LogpSleep(kLogpLogFlushIntervalMsec);
  }
}
Beispiel #13
0
// Initializes a log file at the re-initialization phase.
_Use_decl_annotations_ VOID static LogpReinitializationRoutine(
    _DRIVER_OBJECT *driver_object, PVOID context, ULONG count) {
  PAGED_CODE();
  UNREFERENCED_PARAMETER(driver_object);
  UNREFERENCED_PARAMETER(count);
  NT_ASSERT(context);

  auto info = reinterpret_cast<LogBufferInfo *>(context);
  auto status = LogpInitializeLogFile(info);
  NT_ASSERT(NT_SUCCESS(status));
  if (NT_SUCCESS(status)) {
    HYPERPLATFORM_LOG_INFO("The log file has been activated.");
  }
}
Beispiel #14
0
// Remembers a SYSTEM token and its owner name if applicable
_Use_decl_annotations_ static bool EopmonpCheckProcessToken(HANDLE pid,
                                                            void* context) {
  PAGED_CODE();
  UNREFERENCED_PARAMETER(context);

  const char* NTAPI PsGetProcessImageFileName(_In_ PEPROCESS Process);

  // Get EPROCESS
  PEPROCESS process = nullptr;
  auto status = PsLookupProcessByProcessId(pid, &process);
  if (!NT_SUCCESS(status)) {
    return true;
  }

  // Test if a process name of this pid matches with any of known system
  // processes.
  const auto process_name = PsGetProcessImageFileName(process);
  for (auto system_process_name : kEopmonpSystemProcessNames) {
    if (!RtlEqualMemory(process_name, system_process_name,
                        strlen(system_process_name) + 1)) {
      continue;
    }

    // System process found
    const auto token = PsReferencePrimaryToken(process);

    // Initialize g_eopmonp_offset_to_token if not yet
    if (!g_eopmonp_offset_to_token && !EopmonpInitTokenOffset(process, token)) {
      PsDereferencePrimaryToken(token);
      ObfDereferenceObject(process);
      return false;  // error. cannot continue
    }

    // PLACE TO IMPROVE:
    // EopMon updates a list of system processes' tokens and IDs only once,
    // while some of them like csrss.exe and winlogon.exe can be terminated and
    // re-launched when a use logout and logon to the system. One solution would
    // be installing process notification callback and maintain the latest
    // system process list.
    g_eopmonp_system_process_tokens->emplace_back(token, system_process_name);
    g_eopmonp_system_process_ids->push_back(pid);
    HYPERPLATFORM_LOG_INFO("System Token %p with PID=%Iu %s", token, pid,
                           system_process_name);

    PsDereferencePrimaryToken(token);
  }

  ObfDereferenceObject(process);
  return true;
}
Beispiel #15
0
// Search EPROCESS::Token offset from a pair of EPROCESS and token
_Use_decl_annotations_ static bool EopmonpInitTokenOffset(PEPROCESS process,
                                                          PACCESS_TOKEN token) {
  PAGED_CODE();

  // Search up to a 0x80 pointers size
  for (auto offset = 0ul; offset < sizeof(void*) * 0x80;
       offset += sizeof(void*)) {
    const auto address = reinterpret_cast<ULONG_PTR>(process) + offset;
    const auto possible_token = EopmonpGetProceesTokenByAddress(address);
    if (possible_token == token) {
      g_eopmonp_offset_to_token = offset;
      HYPERPLATFORM_LOG_INFO("EPROCESS::Token offset = %x", offset);
      return true;
    }
  }

  HYPERPLATFORM_LOG_ERROR("Token could not found within an expected range.");
  return false;
}
Beispiel #16
0
// Checks if the system supports virtualization
_Use_decl_annotations_ static bool VmpIsVmxAvailable() {
  PAGED_CODE();

  // See: DISCOVERING SUPPORT FOR VMX
  // If CPUID.1:ECX.VMX[bit 5]=1, then VMX operation is supported.
  int cpu_info[4] = {};
  __cpuid(cpu_info, 1);
  const CpuFeaturesEcx cpu_features = {static_cast<ULONG_PTR>(cpu_info[2])};
  if (!cpu_features.fields.vmx) {
    HYPERPLATFORM_LOG_ERROR("VMX features are not supported.");
    return false;
  }

  // See: BASIC VMX INFORMATION
  // The first processors to support VMX operation use the write-back type.
  const Ia32VmxBasicMsr vmx_basic_msr = {UtilReadMsr64(Msr::kIa32VmxBasic)};
  if (static_cast<memory_type>(vmx_basic_msr.fields.memory_type) !=
      memory_type::kWriteBack) {
    HYPERPLATFORM_LOG_ERROR("Write-back cache type is not supported.");
    return false;
  }

  // See: ENABLING AND ENTERING VMX OPERATION
  Ia32FeatureControlMsr vmx_feature_control = {
      UtilReadMsr64(Msr::kIa32FeatureControl)};
  if (!vmx_feature_control.fields.lock) {
    HYPERPLATFORM_LOG_INFO("The lock bit is clear. Attempting to set 1.");
    const auto status = UtilForEachProcessor(VmpSetLockBitCallback, nullptr);
    if (!NT_SUCCESS(status)) {
      return false;
    }
  }
  if (!vmx_feature_control.fields.enable_vmxon) {
    HYPERPLATFORM_LOG_ERROR("VMX features are not enabled.");
    return false;
  }

  if (!EptIsEptAvailable()) {
    HYPERPLATFORM_LOG_ERROR("EPT features are not fully supported.");
    return false;
  }
  return true;
}
Beispiel #17
0
_Use_decl_annotations_ NTSTATUS
LogInitialization(ULONG flag, const wchar_t *log_file_path) {
  PAGED_CODE();

  auto status = STATUS_SUCCESS;

  g_logp_debug_flag = flag;

  // Initialize a log file if a log file path is specified.
  bool need_reinitialization = false;
  if (log_file_path) {
    status = LogpInitializeBufferInfo(log_file_path, &g_logp_log_buffer_info);
    if (status == STATUS_REINITIALIZATION_NEEDED) {
      need_reinitialization = true;
    } else if (!NT_SUCCESS(status)) {
      return status;
    }
  }

  // Test the log.
  status = HYPERPLATFORM_LOG_INFO("Log has been %sinitialized.",
                                  (need_reinitialization ? "partially " : ""));
  if (!NT_SUCCESS(status)) {
    goto Fail;
  }
  HYPERPLATFORM_LOG_DEBUG("Info= %p, Buffer= %p %p, File= %S",
                          &g_logp_log_buffer_info,
                          g_logp_log_buffer_info.log_buffer1,
                          g_logp_log_buffer_info.log_buffer2, log_file_path);
  return (need_reinitialization ? STATUS_REINITIALIZATION_NEEDED
                                : STATUS_SUCCESS);

Fail:;
  if (log_file_path) {
    LogpFinalizeBufferInfo(&g_logp_log_buffer_info);
  }
  return status;
}
Beispiel #18
0
// Terminates a given process and wait for its completion.
_Use_decl_annotations_ static void EopmonpTerminateProcessWorkerRoutine(
    void* parameter) {
  PAGED_CODE();

  // HYPERPLATFORM_COMMON_DBG_BREAK();

  const auto context = reinterpret_cast<EopmonWorkQueueItem*>(parameter);
  const auto dodgy_pid = context->dodgy_pid;
  const auto system_process_name = context->system_process_name;

  const auto process_handle = EopmonpOpenProcess(dodgy_pid);
  if (!process_handle) {
    goto exit;
  }

  // Terminate it and wait
  auto status = EopmonpTerminateProcessTree(process_handle, dodgy_pid);
  if (status == STATUS_PROCESS_IS_TERMINATING) {
    goto exit_with_close;
  }

  // log stuff
  const auto process_path = EopmonpGetProcessPathByHandle(process_handle);
  if (!process_path) {
    HYPERPLATFORM_LOG_INFO(
        "Exploitation detected. Process %Iu has been killed. Stolen token from "
        "%s",
        dodgy_pid, system_process_name);
    goto exit_with_close;
  }

  PEPROCESS process = nullptr;
  status = PsLookupProcessByProcessId(dodgy_pid, &process);
  if (!NT_SUCCESS(status)) {
    HYPERPLATFORM_LOG_INFO(
        "Exploitation detected. Process %Iu has been killed. Stolen token from "
        "%s. Image= %wZ",
        dodgy_pid, system_process_name, process_path);
    ExFreePoolWithTag(process_path, kHyperPlatformCommonPoolTag);
    goto exit_with_close;
  }

  const auto token = PsReferencePrimaryToken(process);
  HYPERPLATFORM_LOG_INFO(
      "Exploitation detected. Process %Iu has been killed. Stolen token %p "
      "from %s. Image= %wZ",
      dodgy_pid, token, system_process_name, process_path);

  PsDereferencePrimaryToken(token);
  ObfDereferenceObject(process);
  ExFreePoolWithTag(process_path, kHyperPlatformCommonPoolTag);

exit_with_close:;
  ZwClose(process_handle);

  // Delete this PID from ones being marked as already queued
  for (auto& pid_being_killed : g_eopmonp_processes_being_killed) {
    if (pid_being_killed == dodgy_pid) {
      pid_being_killed = nullptr;
    }
  }

exit:;
  ExFreePoolWithTag(context, kHyperPlatformCommonPoolTag);
}
Beispiel #19
0
_Use_decl_annotations_ static void PerfpInitialOutputRoutine(
    void* output_context) {
  UNREFERENCED_PARAMETER(output_context);
  HYPERPLATFORM_LOG_INFO("%-45s,%-20s,%-20s", "FunctionName(Line)",
                         "Execution Count", "Elapsed Time");
}