rogxo@home:~$

R0 debug api

内核层调试API

创建调试对象,初始化调试环境: NtCreateDebugObject ==NtDebugActiveProcess== ==DbgkpSetProcessDebugObject== DbgkpMarkProcessPeb

发送模拟消息: DbgkpPostFakeProcessCreateMessages DbgkpPostFakeThreadMessages

发送接收异常调试事件消息: ==KiDispatchException== ==DbgkpQueueMessage== DbgkpSendApiMessage DbgkSendSystemDllMessages DbgkpPostModuleMessages DbgkPostEnclaveModuleMessages DbgkPostModuleMessage ==NtWaitForDebugEvent== ==NtDebugContinue== ==DbgkForwardException==

退出调试清理环境: DbgkpWakeTarget DbgkpFreeDebugEvent ==NtRemoveProcessDebug== ==DbgkClearProcessDebugObject==

NTSTATUS NtCreateDebugObject(
        PHANDLE DebugObjectHandle,
        ACCESS_MASK DesiredAccess,
        POBJECT_ATTRIBUTES ObjectAttributes,
        ULONG Flags)
{
  char bFlags; // si
  CHAR PreviousMode; // r10
  __int64 MmUserProbeAddress; // rcx
  NTSTATUS status; // eax
  _EWOW64PROCESS *Wow64Process; // rax
  unsigned __int16 Machine; // ax
  void *v13; // [rsp+20h] [rbp-68h]
  PDEBUG_OBJECT DebugObject; // [rsp+58h] [rbp-30h] MAPDST BYREF
  void *Handle[4]; // [rsp+60h] [rbp-28h] BYREF

  bFlags = Flags;
  Handle[0] = 0i64;
  DebugObject = 0i64;
  PreviousMode = KeGetCurrentThread()->PreviousMode;
  if ( PreviousMode )                           // KernelMode = 0,UserMode = 1
  {
    // ProbeForWriteHandle(DebugObjectHandle);
    MmUserProbeAddress = 0x7FFFFFFF0000i64;
    if ( DebugObjectHandle < 0x7FFFFFFF0000i64 )
      MmUserProbeAddress = DebugObjectHandle;
    *MmUserProbeAddress = *MmUserProbeAddress;
  }
  *DebugObjectHandle = 0i64;
  if ( (Flags & 0xFFFFFFFE) != 0 )
    return 0xC000000D;
  status = ObCreateObjectEx(PreviousMode, DbgkDebugObjectType, ObjectAttributes, 
  			PreviousMode, v13, sizeof (DEBUG_OBJECT), 0, 0, &DebugObject, 0i64);
  if ( status >= 0 )
  {
    // ExInitializeFastMutex (&DebugObject->Mutex);
    DebugObject->Mutex.Count = 1;
    DebugObject->Mutex.Owner = 0i64;
    DebugObject->Mutex.Contention = 0;
    KeInitializeEvent(&DebugObject->Mutex.Event, SynchronizationEvent, 0);
    // InitializeListHead (&DebugObject->EventList);
    DebugObject->EventList.Blink = &DebugObject->EventList;
    DebugObject->EventList.Flink = &DebugObject->EventList;
    KeInitializeEvent(&DebugObject->EventsPresent, NotificationEvent, 0);
    if ( (bFlags & 1) != 0 )                    // Flags & DEBUG_KILL_ON_CLOSE
      DebugObject->Flags = 2;                   // DEBUG_OBJECT_KILL_ON_CLOSE
    else
      DebugObject->Flags = 0;
    Wow64Process = KeGetCurrentThread()->ApcState.Process.WoW64Process;
    if ( Wow64Process )
    {
      Machine = Wow64Process->Machine;
      // #define IMAGE_FILE_MACHINE_I386 0x014c  // Intel 386.
      if ( Machine == 0x14C || Machine == 0x1C4 )
        DebugObject->Flags |= 4u;
    }
    // 把调试对象插入到调试进程的句柄表中,其中句柄的权限就是R3传入的DesriedAccess;
    status = ObInsertObjectEx(DebugObject, 0i64, DesiredAccess, 0, 0, 0i64, Handle);
    if ( status >= 0 )
      *DebugObjectHandle = Handle[0];           // Teb->DbgSsReserved[1]
  }
  return status;
}

NTSTATUS __fastcall NtDebugActiveProcess(HANDLE ProcessHandle, HANDLE DebugHandle)
{
  CHAR PreviousMode; // bp
  NTSTATUS status; // eax MAPDST
  PKTHREAD CurrentThread; // rax
  PEPROCESS CurrentProcess; // rsi
  PEWOW64PROCESS WoW64Process; // rax
  USHORT Machine; // cx
  PEWOW64PROCESS TargetWoW64Process; // rax
  USHORT TargetMachine; // cx
  NTSTATUS MsgStatus; // eax
  PETHREAD LastThread; // [rsp+40h] [rbp-28h] BYREF
  PEPROCESS TargetProcess; // [rsp+80h] [rbp+18h] MAPDST BYREF
  PDEBUG_OBJECT DebugObject; // [rsp+88h] [rbp+20h] MAPDST BYREF

  TargetProcess = 0i64;
  PreviousMode = KeGetCurrentThread()->PreviousMode;
  LastThread = 0i64;
  status = ObReferenceObjectByHandleWithTag(
             ProcessHandle,
             0x800u,                            // PROCESS_SET_PORT
             PsProcessType,
             PreviousMode,
             'OgbD',
             &TargetProcess,
             0i64);
  if ( status >= 0 )
  {
    CurrentThread = KeGetCurrentThread();
    CurrentProcess = CurrentThread->ApcState.Process;// PsGetCurrentProcess()
    if ( TargetProcess == CurrentProcess || TargetProcess == PsInitialSystemProcess )
    {
      status = 0xC0000022;                      // STATUS_ACCESS_DENIED
    }
    else if ( PsTestProtectedProcessIncompatibility(PreviousMode, CurrentThread->ApcState.Process, TargetProcess) )
    {
      status = 0xC0000712;                      // STATUS_PROCESS_IS_PROTECTED
    }
    else if ( (TargetProcess->Pcb.SecureState.SecureHandle & 1) == 0
           || (status = PsRequestDebugSecureProcess(TargetProcess, 1u), status >= 0) )
    {
      WoW64Process = CurrentProcess->WoW64Process;
      if ( !WoW64Process
        || (Machine = WoW64Process->Machine, Machine != 0x14C) && Machine != 0x1C4
        || (TargetWoW64Process = TargetProcess->WoW64Process) != 0i64
        && ((TargetMachine = TargetWoW64Process->Machine, TargetMachine == 0x14C) || TargetMachine == 0x1C4) )
      {
        DebugObject = 0i64;
        status = ObReferenceObjectByHandle(DebugHandle, 2u, DbgkDebugObjectType, PreviousMode, &DebugObject, 0i64);
        if ( status >= 0 )
        {
          if ( ExAcquireRundownProtection_0(&TargetProcess->RundownProtect) )
          {
            MsgStatus = DbgkpPostFakeProcessCreateMessages(TargetProcess, DebugObject, &LastThread);
            status = DbgkpSetProcessDebugObject(TargetProcess, DebugObject, MsgStatus, LastThread);
            ExReleaseRundownProtection_0(&TargetProcess->RundownProtect);
          }
          else
          {
            status = 0xC000010A;                // STATUS_PROCESS_IS_TERMINATING
          }
          // ObfDereferenceObjectWithTag(DebugObject)
          HalPutDmaAdapter(DebugObject);
        }
      }
      else
      {
        status = 0xC00000BB;                    // STATUS_NOT_SUPPORTED
      }
    }
    ObfDereferenceObjectWithTag(TargetProcess, 'OgbD');
  }
  return status;
}

NTSTATUS __stdcall DbgkpPostFakeProcessCreateMessages(
        PEPROCESS Process,
        PDEBUG_OBJECT DebugObject,
        PETHREAD *pLastThread)
{
  NTSTATUS status; // eax
  PETHREAD FirstThread; // [rsp+30h] [rbp-68h] BYREF
  PETHREAD LastThread; // [rsp+38h] [rbp-60h] MAPDST BYREF
  KAPC_STATE ApcState; // [rsp+40h] [rbp-58h] BYREF

  // This routine posts the faked initial process create, thread create and mudule load messages
  // 调试假消息的意义在于附加时进程已经创建,无法还原线程进程创建时场景
  // 因此采取模拟发送假消息方式进行折中,还原进程刚创建时的调试信息不会遗漏。
  LastThread = 0i64;
  FirstThread = 0i64;
  memset(&ApcState, 0, sizeof(ApcState));
  LastThread = 0i64;
  status = DbgkpPostFakeThreadMessages(Process, DebugObject, 0i64, &FirstThread, &LastThread);
  if ( status >= 0 )
  {
    KiStackAttachProcess(Process, 0, &ApcState);
    DbgkpPostModuleMessages(Process, FirstThread, &DebugObject->EventsPresent);
    KiUnstackDetachProcess(&ApcState, 0i64);
    ObfDereferenceObjectWithTag(FirstThread, 'OgbD');
    status = 0;
  }
  *pLastThread = LastThread;
  return status;
}

NTSTATUS __stdcall DbgkpPostFakeThreadMessages(
        PEPROCESS Process,
        PDEBUG_OBJECT DebugObject,
        PETHREAD StartThread,
        PETHREAD *pFirstThread,
        PETHREAD *pLastThread)
{
  struct _ETHREAD *FirstThread; // r15
  PETHREAD v9; // rdi
  int status; // r12d
  bool v11; // r13
  ULONG v12; // esi
  char v13; // r13
  void *SectionObject; // rcx
  __int64 v15; // rax
  bool v17; // [rsp+30h] [rbp-1E8h]
  struct _ETHREAD *CurrentThread; // [rsp+68h] [rbp-1B0h]
  struct _DBGKM_APIMSG ApiMsg; // [rsp+90h] [rbp-188h] BYREF
  struct _KAPC_STATE ApcState; // [rsp+1A0h] [rbp-78h] BYREF

  memset(&ApcState, 0, sizeof(ApcState));
  memset(&ApiMsg, 0, sizeof(ApiMsg));
  FirstThread = 0i64;
  v9 = 0i64;
  CurrentThread = KeGetCurrentThread();
  status = 0xC0000001;
  if ( StartThread )
  {
    FirstThread = StartThread;
    ObfReferenceObjectWithTag(StartThread, 'OgbD');
  }
  else
  {
    StartThread = PsGetNextProcessThread(Process, 0i64);
  }
  v11 = StartThread == 0i64;
  v17 = StartThread == 0i64;
  while ( StartThread )
  {
    if ( v9 )
      ObfDereferenceObjectWithTag(v9, 'OgbD');
    v9 = StartThread;
    ObfReferenceObjectWithTag(StartThread, 'OgbD');
    if ( (StartThread->Tcb.MiscFlags & 0x400) == 0 )
    {
      if ( (StartThread->CrossThreadFlags & 2) != 0
        || (PsSynchronizeWithThreadInsertion(StartThread, CurrentThread), (StartThread->CrossThreadFlags & 2) != 0) )
      {
        if ( ExAcquireRundownProtection_0(&StartThread->RundownProtect) )
        {
          v12 = 0xA;
          if ( PsSuspendThread(StartThread, 0i64) >= 0 )
            v12 = 0x2A;
        }
        else
        {
          v12 = 0x12;
        }
        memset(&ApiMsg, 0, sizeof(ApiMsg));
        if ( !v11 || (v12 & 0x10) != 0 )
        {
          v13 = 0;
          ApiMsg.ApiNumber = DbgKmCreateThreadApi;
          ApiMsg.u.Exception.ExceptionRecord.FileHandle = StartThread->Win32StartAddress;// StartAddress
        }
        else
        {
          v13 = 1;
          ApiMsg.ApiNumber = DbgKmCreateProcessApi;
          SectionObject = Process->SectionObject;
          if ( SectionObject )
            ApiMsg.u.Exception.ExceptionRecord.FileHandle = DbgkpSectionToFileHandle(SectionObject);
          else
            ApiMsg.u.Exception.ExceptionRecord.FileHandle = 0i64;
          ApiMsg.u.Exception.ExceptionRecord.BaseOfImage = Process->SectionBaseAddress;
          KeStackAttachProcess(&Process->Pcb, &ApcState);
          v15 = RtlImageNtHeader(Process->SectionBaseAddress);
          if ( v15 )
          {
            ApiMsg.u.ErrorMsg.ExceptionRecord.ExceptionInformation[1] = 0i64;
            ApiMsg.u.LoadDll.NamePointer = *(v15 + 12);
          }
          KeUnstackDetachProcess(&ApcState);
        }
        status = DbgkpQueueMessage(Process, StartThread, &ApiMsg, v12, DebugObject);
        if ( status < 0 )
        {
          if ( (v12 & 0x20) != 0 )
            PsResumeThread(StartThread, 0i64);
          if ( (v12 & 8) != 0 )
            ExReleaseRundownProtection_0(&StartThread->RundownProtect);
          if ( ApiMsg.ApiNumber == DbgKmCreateProcessApi && ApiMsg.u.Exception.ExceptionRecord.FileHandle )
            ObCloseHandle(ApiMsg.u.Exception.ExceptionRecord.FileHandle, 0);
          PsQuitNextProcessThread(StartThread);
          break;
        }
        if ( v13 )
        {
          v11 = 0;
          v17 = 0;
          ObfReferenceObjectWithTag(StartThread, 'OgbD');
          FirstThread = StartThread;
          DbgkSendSystemDllMessages(StartThread, DebugObject, &ApiMsg);
        }
        else
        {
          v11 = v17;
        }
      }
    }
    StartThread = PsGetNextProcessThread(Process, StartThread);
  }
  if ( status >= 0 )
  {
    if ( FirstThread )
    {
      *pFirstThread = FirstThread;
      *pLastThread = v9;
    }
    else
    {
      if ( v9 )
        ObfDereferenceObjectWithTag(v9, 'OgbD');
      return 0xC0000001;
    }
  }
  else
  {
    if ( FirstThread )
      ObfDereferenceObjectWithTag(FirstThread, 'OgbD');
    if ( v9 )
      ObfDereferenceObjectWithTag(v9, 'OgbD');
  }
  return status;
}

HANDLE __stdcall DbgkpSectionToFileHandle(PVOID SectionObject)
{
  POBJECT_NAME_INFORMATION v1; // rdi
  NTSTATUS v2; // ebx
  struct _IO_STATUS_BLOCK IoStatusBlock; // [rsp+30h] [rbp-40h] BYREF
  OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+40h] [rbp-30h] BYREF
  POBJECT_NAME_INFORMATION FileNameInfo; // [rsp+88h] [rbp+18h] BYREF
  HANDLE FileHandle; // [rsp+90h] [rbp+20h] BYREF

  *(&ObjectAttributes.Length + 1) = 0;
  *(&ObjectAttributes.Attributes + 1) = 0;
  FileHandle = 0i64;
  FileNameInfo = 0i64;
  IoStatusBlock = 0i64;
  if ( MmGetFileNameForSection(SectionObject, &FileNameInfo) < 0 )
    return 0i64;
  v1 = FileNameInfo;
  ObjectAttributes.RootDirectory = 0i64;
  ObjectAttributes.ObjectName = &FileNameInfo->Name;
  ObjectAttributes.Length = 48;
  *&ObjectAttributes.SecurityDescriptor = 0i64;
  ObjectAttributes.Attributes = 1600;
  v2 = ZwOpenFile(&FileHandle, 0x80100000, &ObjectAttributes, &IoStatusBlock, 7u, 0x20u);
  ExFreePoolWithTag(v1, 0);
  if ( v2 < 0 )
    return 0i64;
  else
    return FileHandle;
}

void __fastcall DbgkSendSystemDllMessages(PETHREAD Thread, PDEBUG_OBJECT DebugObject, PDBGKM_APIMSG ApiMsg)
{
  struct _EPROCESS *Process; // r15
  union _DBGKM_APIMSG::$1C0BB51BD40DD7F329A455188E31308E *ApiMsgUnionData; // rsi
  int i; // r14d
  PPS_SYSTEM_DLL_INFO SystemDllInfo; // rax MAPDST
  __int64 BaseAddress; // r13
  PIMAGE_NT_HEADERS NtHeader; // rax
  struct _KTHREAD *CurrentThread; // rcx
  char v13; // [rsp+30h] [rbp-108h]
  PTEB Teb; // [rsp+38h] [rbp-100h]
  OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+88h] [rbp-B0h] BYREF
  struct _IO_STATUS_BLOCK IoStatusBlock; // [rsp+B8h] [rbp-80h] BYREF
  struct _KAPC_STATE ApcState; // [rsp+C8h] [rbp-70h] BYREF

  memset(&ApcState, 0, sizeof(ApcState));
  IoStatusBlock = 0i64;
  memset(&ObjectAttributes, 0, sizeof(ObjectAttributes));
  if ( Thread )
    Process = Thread->Tcb.Process;
  else
    Process = KeGetCurrentThread()->ApcState.Process;
  ApiMsgUnionData = &ApiMsg->u;
  for ( i = 0; i < 6; ++i )
  {
    SystemDllInfo = PsQuerySystemDllInfo(i);
    if ( SystemDllInfo
      && (i <= 0 || *(&SystemDllInfo->1 + 1) && Process->WoW64Process && i == PsWow64GetProcessNtdllType(Process)) )
    {
      *&ApiMsgUnionData->Exception.ExceptionRecord.SubSystemKey = 0i64;
      *&ApiMsgUnionData->ErrorMsg.ExceptionRecord.ExceptionAddress = 0i64;
      Teb = 0i64;
      BaseAddress = SystemDllInfo->BaseAddress;
      ApiMsgUnionData->Exception.ExceptionRecord.FileHandle = BaseAddress;
      if ( Thread && i )
      {
        v13 = 1;
        KiStackAttachProcess(Process, 0, &ApcState);
      }
      else
      {
        v13 = 0;
      }
      NtHeader = RtlImageNtHeader(BaseAddress);
      if ( NtHeader )
      {
        ApiMsgUnionData->LoadDll.DebugInfoFileOffset = NtHeader->FileHeader.PointerToSymbolTable;
        ApiMsgUnionData->LoadDll.DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols;
      }
      if ( !Thread )
      {
        CurrentThread = KeGetCurrentThread();
        if ( (CurrentThread->MiscFlags & 0x400) != 0 || CurrentThread->ApcStateIndex == 1 )
          Teb = 0i64;
        else
          Teb = CurrentThread->Teb;
        if ( Teb )
        {
          RtlStringCbCopyW(Teb->StaticUnicodeBuffer, 0x20Aui64, *&SystemDllInfo[1].Flags);
          Teb->NtTib.ArbitraryUserPointer = Teb->StaticUnicodeBuffer;
          ApiMsgUnionData->LoadDll.NamePointer = &Teb->NtTib.ArbitraryUserPointer;
        }
      }
      if ( v13 )
        KiUnstackDetachProcess(&ApcState, 0i64);
      ObjectAttributes.Length = 48;
      ObjectAttributes.RootDirectory = 0i64;
      ObjectAttributes.Attributes = 1600;
      ObjectAttributes.ObjectName = &SystemDllInfo->DllPath;
      *&ObjectAttributes.SecurityDescriptor = 0i64;
      if ( ZwOpenFile(ApiMsgUnionData, 0x80100000, &ObjectAttributes, &IoStatusBlock, 7u, 0x20u) < 0 )
        ApiMsgUnionData->LoadDll.FileHandle = 0i64;
      ApiMsg->h.u1.Length = 5242920;
      ApiMsg->h.u2.ZeroInit = 8;
      ApiMsg->ApiNumber = DbgKmLoadDllApi;
      if ( Thread )
      {
        if ( DbgkpQueueMessage(Process, Thread, ApiMsg, 2u, DebugObject) < 0 && ApiMsgUnionData->LoadDll.FileHandle )
          ObCloseHandle(ApiMsgUnionData->LoadDll.FileHandle, 0);
      }
      else
      {
        DbgkpSendApiMessage(Process);
        if ( ApiMsgUnionData->LoadDll.FileHandle )
          ObCloseHandle(ApiMsgUnionData->LoadDll.FileHandle, 0);
        if ( Teb )
          Teb->NtTib.ArbitraryUserPointer = 0i64;
      }
    }
  }
}