Ejemplo n.º 1
0
_Use_decl_annotations_ EXTERN_C NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
  UNREFERENCED_PARAMETER(RegistryPath);
  PAGED_CODE();

  auto status = STATUS_UNSUCCESSFUL;
  DriverObject->DriverUnload = DriverUnload;

  DBG_BREAK();

  status = LogInitialization(LOG_LEVEL, nullptr);
  if (!NT_SUCCESS(status)) {
    return status;
  }

  // Build the following code as a SYSENTER handler on NonPagedPool
  //
  // FF 25 00 00 00 00                       jmp     cs:jmp_address
  // FF FF FF FF FF FF FF FF jmp_address     dq 0FFFFFFFFFFFFFFFFh
  const JMP_CODE jmpCode = {{0xff, 0x25}, __readmsr(IA32_LSTAR)};

  g_Trampoline = reinterpret_cast<UCHAR*>(ExAllocatePoolWithTag(
      NonPagedPoolExecute, sizeof(jmpCode), POOL_TAG_NAME));
  if (!g_Trampoline) {
    LogTermination();
    return STATUS_MEMORY_NOT_ALLOCATED;
  }
  RtlCopyMemory(g_Trampoline, &jmpCode, sizeof(jmpCode));

  // Modify MSR
  UtilForEachProcessor(MsrHookCallback, nullptr);
  return status;
}
Ejemplo n.º 2
0
_Use_decl_annotations_ EXTERN_C static void VminitpLaunchVM() {
  size_t errorCode = 0;
  auto vmxStatus =
      static_cast<VMX_STATUS>(__vmx_vmread(VM_INSTRUCTION_ERROR, &errorCode));
  if (vmxStatus != VMX_OK) {
    LOG_WARN("VM_INSTRUCTION_ERROR = %p %d", errorCode, vmxStatus);
  }
  DBG_BREAK();
  vmxStatus = static_cast<VMX_STATUS>(__vmx_vmlaunch());

  // Here is not be executed with successful vmlaunch. Instead, the context
  // jumps to an address specified by GUEST_RIP.
  if (vmxStatus == VMX_ERROR_WITH_STATUS) {
    vmxStatus =
        static_cast<VMX_STATUS>(__vmx_vmread(VM_INSTRUCTION_ERROR, &errorCode));
    LOG_ERROR("VM_INSTRUCTION_ERROR = %p %d", errorCode, vmxStatus);
  }
  DBG_BREAK();
}
Ejemplo n.º 3
0
_Use_decl_annotations_ EXTERN_C static void DriverUnload(
    PDRIVER_OBJECT DriverObject) {
  UNREFERENCED_PARAMETER(DriverObject);
  PAGED_CODE();

  DBG_BREAK();

  // Restore MSR
  UtilForEachProcessor(MsrHookCallback, nullptr);
  ExFreePoolWithTag(g_Trampoline, POOL_TAG_NAME);
  LogTermination();
}
Ejemplo n.º 4
0
// Switch the current log buffer and save the contents of old buffer to the log
// file. This function does not flush the log file, so code should call
// LogpWriteMessageToFile() or ZwFlushBuffersFile() later.
EXTERN_C static NTSTATUS LogpWriteLogBufferToFile(
    _In_opt_ LogBufferInfo *Info) {
  NT_ASSERT(Info);
  NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

  auto status = STATUS_SUCCESS;

  // Enter a critical section and acquire a reader lock for Info in order to
  // write a log file safely.
  ExEnterCriticalRegionAndAcquireResourceExclusive(&Info->Resource);

  // Acquire a spin lock for Info.LogBuffer(s) in order to switch its head
  // safely.
  const auto irql = KeAcquireSpinLockRaiseToDpc(&Info->SpinLock);
  auto oldLogBuffer = const_cast<char *>(Info->LogBufferHead);
  if (oldLogBuffer[0]) {
    Info->LogBufferHead = (oldLogBuffer == Info->LogBuffer1) ? Info->LogBuffer2
                                                             : Info->LogBuffer1;
    Info->LogBufferHead[0] = '\0';
    Info->LogBufferTail = Info->LogBufferHead;
  }
  KeReleaseSpinLock(&Info->SpinLock, irql);

  // Write all log entries in old log buffer.
  IO_STATUS_BLOCK ioStatus = {};
  for (auto currentLogEntry = oldLogBuffer; currentLogEntry[0]; /**/) {
    const auto currentLogEntryLength = strlen(currentLogEntry);
    status =
        ZwWriteFile(Info->LogFileHandle, nullptr, nullptr, nullptr, &ioStatus,
                    currentLogEntry, static_cast<ULONG>(currentLogEntryLength),
                    nullptr, nullptr);
    if (!NT_SUCCESS(status)) {
      // It could happen when you did not register IRP_SHUTDOWN and call
      // LogIrpShutdownHandler() and the system tried to log to a file after
      // a filesystem was unmounted.
      DBG_BREAK();
    }

    currentLogEntry += currentLogEntryLength + 1;
  }
  oldLogBuffer[0] = '\0';

  ExReleaseResourceAndLeaveCriticalRegion(&Info->Resource);
  return status;
}
Ejemplo n.º 5
0
// Logs the current log entry to and flush the log file.
EXTERN_C static NTSTATUS LogpWriteMessageToFile(
    _In_ const char *Message, _In_ const LogBufferInfo &Info) {
  NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

  IO_STATUS_BLOCK ioStatus = {};
  auto status =
      ZwWriteFile(Info.LogFileHandle, nullptr, nullptr, nullptr, &ioStatus,
                  const_cast<char *>(Message),
                  static_cast<ULONG>(strlen(Message)), nullptr, nullptr);
  if (!NT_SUCCESS(status)) {
    // It could happen when you did not register IRP_SHUTDOWN and call
    // LogIrpShutdownHandler() and the system tried to log to a file after
    // a filesystem was unmounted.
    DBG_BREAK();
  }
  status = ZwFlushBuffersFile(Info.LogFileHandle, &ioStatus);
  return status;
}
Ejemplo n.º 6
0
EXTERN_C static void LogpFinalizeBufferInfo(
    _In_opt_ PDEVICE_OBJECT DeviceObject, _In_ LogBufferInfo *Info) {
  PAGED_CODE();
  NT_ASSERT(Info);

  // Closing the log buffer flush thread.
  if (Info->BufferFlushThreadHandle) {
    Info->BufferFlushThreadShouldBeAlive = false;
    auto status =
        ZwWaitForSingleObject(Info->BufferFlushThreadHandle, FALSE, nullptr);
    if (!NT_SUCCESS(status)) {
      DBG_BREAK();
    }
    ZwClose(Info->BufferFlushThreadHandle);
    Info->BufferFlushThreadHandle = nullptr;
  }

  // Cleaning up other things.
  if (Info->LogFileHandle) {
    ZwClose(Info->LogFileHandle);
    Info->LogFileHandle = nullptr;
  }
  if (Info->LogBuffer2) {
    ExFreePoolWithTag(Info->LogBuffer2, LOGP_POOL_TAG_NAME);
    Info->LogBuffer2 = nullptr;
  }
  if (Info->LogBuffer1) {
    ExFreePoolWithTag(Info->LogBuffer1, LOGP_POOL_TAG_NAME);
    Info->LogBuffer1 = nullptr;
  }

  if (DeviceObject) {
    IoUnregisterShutdownNotification(DeviceObject);
  }
  if (Info->ResourceInitialized) {
  ExDeleteResourceLite(&Info->Resource);
    Info->ResourceInitialized = false;
  }
}
Ejemplo n.º 7
0
EXTERN_C static
void Win8pDetectPatchGuardWorkItem(
    __inout WORK_QUEUE_ITEM* Item,
    __in ULONG64 CallerId)  // For debugging
{
    PAGED_CODE();

    // It should be by the SYSTEM process when it was called from
    // ExpWorkerThread
    if (PsGetCurrentProcessId() != reinterpret_cast<HANDLE>(4))
    {
        return;
    }

    // And of course, the Work Item should be valid. Be-aware, we are not
    // filtering DCP routines that may use a non-canonical address.
    if (Item < MmSystemRangeStart ||
        !Win8pIsAccessibleAddress(Item))
    {
        return;
    }

    if (Item->WorkerRoutine < MmSystemRangeStart ||
        !Win8pIsAccessibleAddress(Item->WorkerRoutine))
    {
        return;
    }

    // 0 = KiCommitThreadWait, 1 = KiAttemptFastRemovePriQueue
    //  It seems that the value is always 0 though
    if (CallerId == 1)
    {
        DBG_BREAK();
    }

    PgContext_8_1* pgContext = nullptr;

    // It is a PatchGuard context if the routine is KiScbQueueScanWorker
    if (reinterpret_cast<ULONG_PTR>(Item->WorkerRoutine)
        == g_Symbols.KiScbQueueScanWorker)
    {
        // Decode parameter by doing the same things as KiScbQueueScanWorker
        auto* param = reinterpret_cast<Pg_KiScbQueueScanWorkerContext*>(
            Item->Parameter);
        ULONG64 routine = param->EncodedRoutine ^ param->XorKey;
        ULONG64 context = param->EncodedPgContext ^ param->XorKey;
        DBG_PRINT("[%5Iu:%5Iu] PatchGuard %016llX :"
                  " KiScbQueueScanWorker (%016llX) was dequeued.\n",
            reinterpret_cast<ULONG_PTR>(PsGetCurrentProcessId()),
            reinterpret_cast<ULONG_PTR>(PsGetCurrentThreadId()),
            context, routine);

        pgContext = reinterpret_cast<PgContext_8_1*>(context);
    }
    // It is PatchGuard context if the routine is FsRtlUninitializeSmallMcb.
    else if (*reinterpret_cast<ULONG_PTR*>(Item->WorkerRoutine)
        == WIN8_FsRtlUninitializeSmallMcb_PATTERN)
    {
        DBG_PRINT("[%5Iu:%5Iu] PatchGuard %p :"
                  " FsRtlUninitializeSmallMcb (%p) was dequeued.\n",
            reinterpret_cast<ULONG_PTR>(PsGetCurrentProcessId()),
            reinterpret_cast<ULONG_PTR>(PsGetCurrentThreadId()),
            Item->Parameter, Item->WorkerRoutine);

        pgContext = reinterpret_cast<PgContext_8_1*>(Item->Parameter);
    }
    else
    {
        // Neither KiScbQueueScanWorker nor FsRtlUninitializeSmallMcb. benign.
        return;
    }

    if (Win8pIsMonitoringModeEnabled())
    {
        // Now, we have got a decrypted PatchGuard context that is about to be
        // fetched by ExpWorkerThread.
        Win8pPatchPgContext(pgContext);
    }
    else
    {
        // You can replace the routine with a harmless empty function instead of
        // modifying the PatchGuard context.
        Item->WorkerRoutine = [](void*){};
    }
}