win内核调试原理揭秘2

Posted by Qmeimei10086 on July 12, 2026

ok啊我们继续来分析DbgkpPostFakeProcessCreateMessages和DbgkpSetProcessDebugObject

DbgkpPostFakeProcessCreateMessages

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Process -> 被调试进程对象
// 
// 
// NTSTATUS
// DbgkpPostFakeProcessCreateMessages (
//     IN PEPROCESS Process,
//     IN PDEBUG_OBJECT DebugObject,
//     IN PETHREAD *pLastThread
//     )
NTSTATUS DbgkpPostFakeProcessCreateMessages(PEPROCESS Process, PDEBUG_OBJECT DebugObject, PETHREAD *pLastThread)
{
  struct _KTHREAD *v4; // rbx
  NTSTATUS result; // eax
  PETHREAD FirstThread; // [rsp+30h] [rbp-68h] BYREF
  PETHREAD LastThread; // [rsp+38h] [rbp-60h] BYREF
  _KAPC_STATE apc; // [rsp+40h] [rbp-58h] BYREF

  v4 = 0;
  FirstThread = 0;
  memset(&apc, 0, sizeof(apc));
  LastThread = 0;
  result = DbgkpPostFakeThreadMessages(Process, DebugObject, 0, &FirstThread, &LastThread);
  if ( result >= 0 )
  {
    KiStackAttachProcess((ULONG_PTR)Process);
    DbgkpPostModuleMessages(Process, FirstThread, &DebugObject->EventsPresent);
    KiUnstackDetachProcess(&apc, 0);
    ObfDereferenceObjectWithTag(FirstThread, 0x4F676244u);
    result = 0;
    v4 = LastThread;
  }
  *pLastThread = v4;
  return result;
}

有发送线程假消息和和模块假消息
模块假消息不难,发的主要是一些加载了哪些dll啦之类的,但是我们要拿这些信息需要被调试进程的上下文,所以KiStackAttachProcess一下
DbgkpPostModuleMessages不难,我们重点看DbgkpPostFakeThreadMessages

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
NTSTATUS DbgkpPostFakeThreadMessages(
        PEPROCESS Process,
        PDEBUG_OBJECT DebugObject,
        PETHREAD StartThread,
        PETHREAD *pFirstThread,
        PETHREAD *pLastThread)
{
  PETHREAD CurrentProcessThread; // rbx
  struct _ETHREAD *FirstThread; // r15
  struct _ETHREAD *LastThread; // rdi
  int status; // r12d
  bool IsFirstThread; // r13
  ULONG flag; // esi 这边的flag都是debug_event的flag
  char IsProcessCreate; // r13
  void *SectionObject; // rcx
  PIMAGE_NT_HEADERS NT_HEADERS; // rax
  bool NotFirstThread; // [rsp+30h] [rbp-1E8h]
  struct _KTHREAD *CurrentThread; // [rsp+68h] [rbp-1B0h]
  DBGKM_APIMSG DbgKM_ApiMSG; // [rsp+90h] [rbp-188h] BYREF 
                             //                            typedef struct _DBGKM_APIMSG {
                             //                                PORT_MESSAGE h;
                             //                                DBGKM_APINUMBER ApiNumber;
                             //                                NTSTATUS ReturnedStatus;
                             //                                union {
                             //                                    DBGKM_EXCEPTION Exception;
                             //                                    DBGKM_CREATE_THREAD CreateThread;
                             //                                    DBGKM_CREATE_PROCESS CreateProcessInfo;
                             //                                    DBGKM_EXIT_THREAD ExitThread;
                             //                                    DBGKM_EXIT_PROCESS ExitProcess;
                             //                                    DBGKM_LOAD_DLL LoadDll;
                             //                                    DBGKM_UNLOAD_DLL UnloadDll;
                             //                                } u;
                             //                            } DBGKM_APIMSG, *PDBGKM_APIMSG;
  struct _KAPC_STATE ApcState; // [rsp+1A0h] [rbp-78h] BYREF

  CurrentProcessThread = StartThread;
  memset(&ApcState, 0, sizeof(ApcState));
  memset(&DbgKM_ApiMSG, 0, 0x110u);
  FirstThread = 0;
  LastThread = 0;
  CurrentThread = KeGetCurrentThread();
  status = 0xC0000001;                          // STATUS_UNSUCCESSFUL
  if ( CurrentProcessThread )
  {
    FirstThread = CurrentProcessThread;
    ObfReferenceObjectWithTag(CurrentProcessThread, 'OgbD');
  }
  else
  {
    CurrentProcessThread = PsGetNextProcessThread(Process, 0);
  }
  IsFirstThread = StartThread == 0;
  NotFirstThread = StartThread == 0;
  while ( CurrentProcessThread )
  {
    if ( LastThread )
      ObfDereferenceObjectWithTag(LastThread, 'OgbD');
    LastThread = CurrentProcessThread;
    ObfReferenceObjectWithTag(CurrentProcessThread, 'OgbD');
    if ( (CurrentProcessThread->Tcb.MiscFlags & 0x400) == 0 )
    {
      if ( (CurrentProcessThread->CrossThreadFlags & 2) != 0
        || (PsSynchronizeWithThreadInsertion(
              (__int64)CurrentProcessThread,
              (__int64)CurrentThread),          // 等待rundown保护锁
            (CurrentProcessThread->CrossThreadFlags & 2) != 0) )
      {
        if ( ExAcquireRundownProtection(&CurrentProcessThread->RundownProtect) )// 
                                                // #define DEBUG_EVENT_READ            (0x01)  // Event had been seen by win32 app
                                                // #define DEBUG_EVENT_NOWAIT          (0x02)  // No waiter one this. Just free the pool
                                                // #define DEBUG_EVENT_INACTIVE        (0x04)  // The message is in inactive. It may be activated or deleted later
                                                // #define DEBUG_EVENT_RELEASE         (0x08)  // Release rundown protection on this thread
                                                // #define DEBUG_EVENT_PROTECT_FAILED  (0x10)  // Rundown protection failed to be acquired on this thread
                                                // #define DEBUG_EVENT_SUSPEND         (0x20)  // Resume thread on continue
        {
          flag = 0xA;                           // A = 2+8
                                                // DEBUG_EVENT_NOWAIT
                                                // DEBUG_EVENT_RELEASE
          if ( (int)PsSuspendThread(CurrentProcessThread, 0) >= 0 )
            flag = 0x2A;                        // 多并一个DEBUG_EVENT_SUSPEND 
        }
        else
        {
          flag = 0x12;
        }
        memset(&DbgKM_ApiMSG, 0, 0x110u);
        if ( !IsFirstThread || (flag & 0x10) != 0 )
        {
          IsProcessCreate = 0;
          DbgKM_ApiMSG.ApiNumber = DbgKmCreateThreadApi;
          DbgKM_ApiMSG.u.CreateProcessInfo.FileHandle = CurrentProcessThread->Win32StartAddress;
        }
        else                                    // 发送进程创建假消息
        {
          IsProcessCreate = 1;
          DbgKM_ApiMSG.ApiNumber = DbgKmCreateProcessApi;
          SectionObject = Process->SectionObject;
          if ( SectionObject )
            DbgKM_ApiMSG.u.CreateProcessInfo.FileHandle = DbgkpSectionToFileHandle(SectionObject);
          else
            DbgKM_ApiMSG.u.CreateProcessInfo.FileHandle = 0;
          DbgKM_ApiMSG.u.CreateProcessInfo.BaseOfImage = Process->SectionBaseAddress;// exe基址
          KeStackAttachProcess(&Process->Pcb, &ApcState);
          NT_HEADERS = RtlImageNtHeader(Process->SectionBaseAddress);
          if ( NT_HEADERS )
          {
            DbgKM_ApiMSG.u.Exception.ExceptionRecord.ExceptionInformation[1] = 0;
            *(_QWORD *)&DbgKM_ApiMSG.u.CreateProcessInfo.DebugInfoFileOffset = *(_QWORD *)&NT_HEADERS->FileHeader.PointerToSymbolTable;// 拿pdb
          }
          KeUnstackDetachProcess(&ApcState);
        }
        status = DbgkpQueueMessage(Process, CurrentProcessThread, &DbgKM_ApiMSG, flag, DebugObject);// 将DBGKM_APIMSG转成DEBUG_EVENT并插入DEBUG_OBJECT的链表
        if ( status < 0 )
        {                                       // 发生错误,清理并跳出循环
          if ( (flag & 0x20) != 0 )
            PsResumeThread(CurrentProcessThread, 0);
          if ( (flag & 8) != 0 )
            ExReleaseRundownProtection(&CurrentProcessThread->RundownProtect);
          if ( DbgKM_ApiMSG.ApiNumber == DbgKmCreateProcessApi
            && DbgKM_ApiMSG.u.Exception.ExceptionRecord.ExceptionRecord )
          {
            ObCloseHandle(DbgKM_ApiMSG.u.Exception.ExceptionRecord.ExceptionRecord, 0);
          }
          PsQuitNextProcessThread(CurrentProcessThread);
          break;
        }
        if ( IsProcessCreate )
        {
          IsFirstThread = 0;
          NotFirstThread = 0;
          ObfReferenceObjectWithTag(CurrentProcessThread, 'OgbD');
          FirstThread = CurrentProcessThread;
          DbgkSendSystemDllMessages((char *)CurrentProcessThread, &DebugObject->EventsPresent, &DbgKM_ApiMSG);
        }
        else
        {
          IsFirstThread = NotFirstThread;
        }
      }
    }
    CurrentProcessThread = PsGetNextProcessThread(Process, CurrentProcessThread);
  }
  if ( status >= 0 )
  {
    if ( FirstThread )
    {
      *pFirstThread = FirstThread;
      *pLastThread = LastThread;
    }
    else
    {
      if ( LastThread )
        ObfDereferenceObjectWithTag(LastThread, 'OgbD');
      return 0xC0000001;
    }
  }
  else
  {
    if ( FirstThread )
      ObfDereferenceObjectWithTag(FirstThread, 'OgbD');
    if ( LastThread )
      ObfDereferenceObjectWithTag(LastThread, 'OgbD');
  }
  return status;
}

首先我们看到多了一个结构体也就是DBGKM_APIMSG,这个是debugevent的成员,记录着关键的调试信息
我们可用看到有个大循环,一开始传进来的StartThread是0 然后一直PsGetNextProcessThread,得到每一个线程的一些关键信息,并且填入DBGKM_APIMSG
最后调用最关键的函数DbgkpQueueMessage
img3 我们可用看到交叉应用,他被很多关键函数调用,比如DbgkpSendApiMessage,这就是异常啦之类的发送调试事件必须用到的函数
这个函数的作用就是,创建一个调试事件,然后把收到的DBGKM_APIMSG写道调试事件的ApiMsg成员里,最后挂入调试对象的双向循环链表里,然后置位调试器信号量,激活调试器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
NTSTATUS DbgkpQueueMessage(
        PEPROCESS Process,
        PETHREAD Thread,
        PDBGKM_APIMSG ApiMsg,
        ULONG Flags,
        PDEBUG_OBJECT TargetDebugObject)
{
  __int64 v10; // r12
  DEBUG_EVENT *alloc_debug_event; // rax
  DEBUG_EVENT *p_debug_event; // r14
  DBGKM_APINUMBER ApiNumber; // ecx
  DBGKM_APIMSG *p_ApiMsg; // rbx
  DBGKM_APIMSG *ApiMsg_From_Debug_Event; // rax
  PDBGKM_APIMSG In_ApiMsg; // rcx
  __int64 v18; // rdx
  __int128 v19; // xmm1
  NTSTATUS Status; // esi
  struct _FAST_MUTEX *p_Mutex; // r12
  struct _LIST_ENTRY *Blink; // rcx
  __int128 v23; // xmm1
  ULONG is_no_wait; // [rsp+30h] [rbp-1C8h]
  DEBUG_EVENT debug_event; // [rsp+40h] [rbp-1B8h] BYREF
                                                //                                                 #define DEBUG_EVENT_READ            (0x01)  // Event had been seen by win32 app
                                                //                                                 #define DEBUG_EVENT_NOWAIT          (0x02)  // No waiter one this. Just free the pool
                                                //                                                 #define DEBUG_EVENT_INACTIVE        (0x04)  // The message is in inactive. It may be activated or deleted later
                                                //                                                 #define DEBUG_EVENT_RELEASE         (0x08)  // Release rundown protection on this thread
                                                //                                                 #define DEBUG_EVENT_PROTECT_FAILED  (0x10)  // Rundown protection failed to be acquired on this thread
                                                //                                                 #define DEBUG_EVENT_SUSPEND         (0x20)  // Resume thread on continue
                                                //                                                 
                                                //                                              
  memset(
    &debug_event,
    0,
    0x168u);
  v10 = 2;
  is_no_wait = Flags & 2;
  if ( (Flags & 2) == 0 )                       // 需等待事件
  {
    debug_event.Flags = Flags;
    p_debug_event = &debug_event;
    ExAcquireFastMutex(&DbgkpProcessDebugPortMutex);
    ApiNumber = ApiMsg->ApiNumber;
    TargetDebugObject = (PDEBUG_OBJECT)Process->DebugPort;// 需等待事件必须有debug port
    if ( (unsigned int)(ApiNumber - 1) <= 1 && (Thread->CrossThreadFlags & 0x40) != 0 )
      TargetDebugObject = 0;
    if ( ApiNumber == DbgKmLoadDllApi )
    {
      if ( ((unsigned __int8)Flags & Thread->CrossThreadFlags & 0x40) == 0 )
      {
LABEL_14:
        KeInitializeEvent(&debug_event.ContinueEvent, SynchronizationEvent, 0);
        goto LABEL_15;
      }
      TargetDebugObject = 0;
    }
    if ( (unsigned int)(ApiNumber - 3) <= 1 && SLOBYTE(Thread->CrossThreadFlags) < 0 )
      TargetDebugObject = 0;
    goto LABEL_14;
  }
  alloc_debug_event = (DEBUG_EVENT *)ExAllocatePoolWithQuotaTag((POOL_TYPE)520, 0x168u, 'EgbD');
  p_debug_event = alloc_debug_event;
  if ( !alloc_debug_event )
    return 0xC000009A;                          // STATUS_INSUFFICIENT_RESOURCES
  alloc_debug_event->Flags = Flags | 4;
  ObfReferenceObjectWithTag(Process, 0x4F676244u);
  ObfReferenceObjectWithTag(Thread, 0x4F676244u);
  p_debug_event->BackoutThread = (PETHREAD)KeGetCurrentThread();
LABEL_15:
  p_ApiMsg = &p_debug_event->ApiMsg;
  p_debug_event->Process = Process;
  ApiMsg_From_Debug_Event = &p_debug_event->ApiMsg;
  p_debug_event->Thread = Thread;
  In_ApiMsg = ApiMsg;
  v18 = 2;
  do                                            // 复制
  {
    *(_OWORD *)&ApiMsg_From_Debug_Event->h.u1.s1.DataLength = *(_OWORD *)&In_ApiMsg->h.u1.s1.DataLength;
    *(union _PORT_MESSAGE::$BD8137A324A8476723CC573F97133CB1 *)((char *)&ApiMsg_From_Debug_Event->h.8 + 8) = *(union _PORT_MESSAGE::$BD8137A324A8476723CC573F97133CB1 *)((char *)&In_ApiMsg->h.8 + 8);
    *(_OWORD *)&ApiMsg_From_Debug_Event->h.ClientViewSize = *(_OWORD *)&In_ApiMsg->h.ClientViewSize;
    *(_OWORD *)&ApiMsg_From_Debug_Event->u.Exception.ExceptionRecord.ExceptionCode = *(_OWORD *)&In_ApiMsg->u.Exception.ExceptionRecord.ExceptionCode;
    *((_OWORD *)&ApiMsg_From_Debug_Event->u.UnloadDll + 1) = *((_OWORD *)&In_ApiMsg->u.UnloadDll + 1);
    *((_OWORD *)&ApiMsg_From_Debug_Event->u.UnloadDll + 2) = *((_OWORD *)&In_ApiMsg->u.UnloadDll + 2);
    *((_OWORD *)&ApiMsg_From_Debug_Event->u.UnloadDll + 3) = *((_OWORD *)&In_ApiMsg->u.UnloadDll + 3);
    ApiMsg_From_Debug_Event = (DBGKM_APIMSG *)((char *)ApiMsg_From_Debug_Event + 128);
    v19 = *((_OWORD *)&In_ApiMsg->u.UnloadDll + 4);
    In_ApiMsg = (PDBGKM_APIMSG)((char *)In_ApiMsg + 128);
    *((_OWORD *)&ApiMsg_From_Debug_Event[-1].u.UnloadDll + 9) = v19;
    --v18;
  }
  while ( v18 );
  *(_OWORD *)&ApiMsg_From_Debug_Event->h.u1.s1.DataLength = *(_OWORD *)&In_ApiMsg->h.u1.s1.DataLength;
  p_debug_event->ClientId = Thread->Cid;
  if ( TargetDebugObject )
  {
    p_Mutex = &TargetDebugObject->Mutex;
    ExAcquireFastMutex(&TargetDebugObject->Mutex);
    if ( (TargetDebugObject->Flags & 1) != 0 )
    {
      Status = 0xC0000354;
    }
    else
    {
      Blink = TargetDebugObject->EventList.Blink;
      if ( Blink->Flink != &TargetDebugObject->EventList )
        __fastfail(3u);                         // 检查完整性
      p_debug_event->EventList.Flink = &TargetDebugObject->EventList;
      p_debug_event->EventList.Blink = Blink;
      Blink->Flink = &p_debug_event->EventList; // 尾插法
      TargetDebugObject->EventList.Blink = &p_debug_event->EventList;
      if ( !is_no_wait )                        // 需等待,假消息不走这
        KeSetEvent(&TargetDebugObject->EventsPresent, 0, 0);
      Status = 0;
    }
    KeReleaseGuardedMutex(p_Mutex);
    v10 = 2;
  }
  else
  {
    Status = 0xC0000353;                        // STATUS_PORT_NOT_SET
  }
  if ( is_no_wait )
  {
    if ( Status < 0 )
    {
      ObfDereferenceObjectWithTag(Process, 0x4F676244u);
      ObfDereferenceObjectWithTag(Thread, 0x4F676244u);
      ExFreePoolWithTag(p_debug_event, 0);
    }
  }
  else
  {
    KeReleaseGuardedMutex(&DbgkpProcessDebugPortMutex);
    if ( Status >= 0 )
    {
      KeWaitForSingleObject(&p_debug_event->ContinueEvent, Executive, 0, 0, 0);
      Status = p_debug_event->Status;
      do
      {
        *(_OWORD *)&ApiMsg->h.u1.s1.DataLength = *(_OWORD *)&p_ApiMsg->h.u1.s1.DataLength;
        *(union _PORT_MESSAGE::$BD8137A324A8476723CC573F97133CB1 *)((char *)&ApiMsg->h.8 + 8) = *(union _PORT_MESSAGE::$BD8137A324A8476723CC573F97133CB1 *)((char *)&p_ApiMsg->h.8 + 8);
        *(_OWORD *)&ApiMsg->h.ClientViewSize = *(_OWORD *)&p_ApiMsg->h.ClientViewSize;
        *(_OWORD *)&ApiMsg->u.Exception.ExceptionRecord.ExceptionCode = *(_OWORD *)&p_ApiMsg->u.Exception.ExceptionRecord.ExceptionCode;
        *((_OWORD *)&ApiMsg->u.UnloadDll + 1) = *((_OWORD *)&p_ApiMsg->u.UnloadDll + 1);
        *((_OWORD *)&ApiMsg->u.UnloadDll + 2) = *((_OWORD *)&p_ApiMsg->u.UnloadDll + 2);
        *((_OWORD *)&ApiMsg->u.UnloadDll + 3) = *((_OWORD *)&p_ApiMsg->u.UnloadDll + 3);
        ApiMsg = (PDBGKM_APIMSG)((char *)ApiMsg + 128);
        v23 = *((_OWORD *)&p_ApiMsg->u.UnloadDll + 4);
        p_ApiMsg = (DBGKM_APIMSG *)((char *)p_ApiMsg + 128);
        *((_OWORD *)&ApiMsg[-1].u.UnloadDll + 9) = v23;
        --v10;
      }
      while ( v10 );
      *(_OWORD *)&ApiMsg->h.u1.s1.DataLength = *(_OWORD *)&p_ApiMsg->h.u1.s1.DataLength;
    }
  }
  return Status;
}

当然他的功能很多,我们发假消息用的flag是

1
2
3
4
5
6
7
8
9
                                                // #define DEBUG_EVENT_READ            (0x01)  // Event had been seen by win32 app
                                                // #define DEBUG_EVENT_NOWAIT          (0x02)  // No waiter one this. Just free the pool
                                                // #define DEBUG_EVENT_INACTIVE        (0x04)  // The message is in inactive. It may be activated or deleted later
                                                // #define DEBUG_EVENT_RELEASE         (0x08)  // Release rundown protection on this thread
                                                // #define DEBUG_EVENT_PROTECT_FAILED  (0x10)  // Rundown protection failed to be acquired on this thread
                                                // #define DEBUG_EVENT_SUSPEND         (0x20)  // Resume thread on continue
          flag = 0xA;                           // A = 2+8
                                                // DEBUG_EVENT_NOWAIT
                                                // DEBUG_EVENT_RELEASE

也就是走的NOWAIT这条路,只会干复制apimsg并且挂到循环链表上面去的活

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  p_ApiMsg = &p_debug_event->ApiMsg;
  p_debug_event->Process = Process;
  ApiMsg_From_Debug_Event = &p_debug_event->ApiMsg;
  p_debug_event->Thread = Thread;
  In_ApiMsg = ApiMsg;
  v18 = 2;
  do                                            // 复制
  {
    *(_OWORD *)&ApiMsg_From_Debug_Event->h.u1.s1.DataLength = *(_OWORD *)&In_ApiMsg->h.u1.s1.DataLength;
    *(union _PORT_MESSAGE::$BD8137A324A8476723CC573F97133CB1 *)((char *)&ApiMsg_From_Debug_Event->h.8 + 8) = *(union _PORT_MESSAGE::$BD8137A324A8476723CC573F97133CB1 *)((char *)&In_ApiMsg->h.8 + 8);
    *(_OWORD *)&ApiMsg_From_Debug_Event->h.ClientViewSize = *(_OWORD *)&In_ApiMsg->h.ClientViewSize;
    *(_OWORD *)&ApiMsg_From_Debug_Event->u.Exception.ExceptionRecord.ExceptionCode = *(_OWORD *)&In_ApiMsg->u.Exception.ExceptionRecord.ExceptionCode;
    *((_OWORD *)&ApiMsg_From_Debug_Event->u.UnloadDll + 1) = *((_OWORD *)&In_ApiMsg->u.UnloadDll + 1);
    *((_OWORD *)&ApiMsg_From_Debug_Event->u.UnloadDll + 2) = *((_OWORD *)&In_ApiMsg->u.UnloadDll + 2);
    *((_OWORD *)&ApiMsg_From_Debug_Event->u.UnloadDll + 3) = *((_OWORD *)&In_ApiMsg->u.UnloadDll + 3);
    ApiMsg_From_Debug_Event = (DBGKM_APIMSG *)((char *)ApiMsg_From_Debug_Event + 128);
    v19 = *((_OWORD *)&In_ApiMsg->u.UnloadDll + 4);
    In_ApiMsg = (PDBGKM_APIMSG)((char *)In_ApiMsg + 128);
    *((_OWORD *)&ApiMsg_From_Debug_Event[-1].u.UnloadDll + 9) = v19;

   ...
                                                  // 挂循环链表上去
    else
    {
      Blink = TargetDebugObject->EventList.Blink;
      if ( Blink->Flink != &TargetDebugObject->EventList )
        __fastfail(3u);                         // 检查完整性
      p_debug_event->EventList.Flink = &TargetDebugObject->EventList;
      p_debug_event->EventList.Blink = Blink;
      Blink->Flink = &p_debug_event->EventList; // 尾插法
      TargetDebugObject->EventList.Blink = &p_debug_event->EventList;
      if ( !is_no_wait )                        // 需等待,假消息不走这
        KeSetEvent(&TargetDebugObject->EventsPresent, 0, 0);
      Status = 0;
    }
    KeReleaseGuardedMutex(p_Mutex);

最后DbgkpPostFakeThreadMessages还会传出处理后的最后一个线程,接下来有用

1
2
      *pFirstThread = FirstThread;
      *pLastThread = LastThread;

DbgkpSetProcessDebugObject

show code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
NTSTATUS DbgkpSetProcessDebugObject(
        PEPROCESS Process,
        PDEBUG_OBJECT DebugObject,
        NTSTATUS MsgStatus,
        PETHREAD LastThread)
{
  struct _ETHREAD *CurrentThread; // r13
  int v5; // edi
  PETHREAD pLastThread_copy; // rbx
  struct _ETHREAD *NextProcessThread; // r14
  struct _LIST_ENTRY *Entry; // r14
  PDEBUG_EVENT DebugEvent; // rbx
  ULONG Flags; // eax
  PETHREAD Thread; // r13
  struct _LIST_ENTRY *Flink; // rcx
  struct _LIST_ENTRY *v15; // rax
  struct _LIST_ENTRY *Blink; // rax
  struct _LIST_ENTRY *p_EventList; // rax
  ULONG v18; // eax
  PVOID v19; // rcx
  __int64 v20; // rax
  PVOID Object; // [rsp+30h] [rbp-30h] BYREF
  struct _ETHREAD *v23; // [rsp+38h] [rbp-28h]
  PKGUARDED_MUTEX Mutex; // [rsp+40h] [rbp-20h]
  PVOID clear_link; // [rsp+48h] [rbp-18h] BYREF
  PDEBUG_EVENT p_clear_link; // [rsp+50h] [rbp-10h]
  bool first; // [rsp+A8h] [rbp+48h]
  char v28; // [rsp+B0h] [rbp+50h]
  PETHREAD pLastThread; // [rsp+B8h] [rbp+58h] BYREF

  pLastThread = LastThread;
  CurrentThread = (struct _ETHREAD *)KeGetCurrentThread();
  Object = 0;
  p_clear_link = (PDEBUG_EVENT)&clear_link;
  clear_link = &clear_link;
  v5 = MsgStatus;
  v23 = CurrentThread;
  first = 1;
  v28 = 0;
  if ( MsgStatus >= 0 )
  {
    pLastThread_copy = pLastThread;
    v5 = 0;
  }
  else
  {
    pLastThread_copy = 0;
    pLastThread = 0;
  }
  if ( v5 >= 0 )
  {
    ExAcquireFastMutex(&DbgkpProcessDebugPortMutex);
    while ( 1 )
    {
      if ( Process->DebugPort )
      {
        v5 = 0xC0000048;                        //     STATUS_PORT_ALREADY_SET
        v28 = 1;
        goto LABEL_11;
      }
      Process->DebugPort = DebugObject;         // 设置被调试进程debugport
      ObfReferenceObjectWithTag(pLastThread_copy, 'OgbD');
      v28 = 1;
      NextProcessThread = PsGetNextProcessThread(Process, pLastThread_copy);
      if ( !NextProcessThread )
        goto LABEL_11;
      Process->DebugPort = 0;                   // 说明又创建了一个线程,再去发假消息
      KeReleaseGuardedMutex(&DbgkpProcessDebugPortMutex);
      v28 = 0;
      ObfDereferenceObjectWithTag(pLastThread_copy, 'OgbD');
      v5 = DbgkpPostFakeThreadMessages(Process, DebugObject, NextProcessThread, (PETHREAD *)&Object, &pLastThread);
      if ( v5 < 0 )
        break;
      ObfDereferenceObjectWithTag(Object, 0x4F676244u);
      ExAcquireFastMutex(&DbgkpProcessDebugPortMutex);
      pLastThread_copy = pLastThread;
    }
    pLastThread_copy = 0;
    pLastThread = 0;
  }
LABEL_11:
  Mutex = &DebugObject->Mutex;
  ExAcquireFastMutex(&DebugObject->Mutex);
  if ( v5 >= 0 )
  {
    if ( (DebugObject->Flags & 1) != 0 )        // 
                                                // #define DEBUG_OBJECT_DELETE_PENDING (0x1) // Debug object is delete pending.
                                                // #define DEBUG_OBJECT_KILL_ON_CLOSE  (0x2) // Kill all debugged processes on close
    {
      Process->DebugPort = 0;
      v5 = 0xC0000354;                          //     STATUS_DEBUGGER_INACTIVE
    }
    else
    {
      _InterlockedOr((volatile signed __int32 *)&Process->___u6, 3u);
      ObfReferenceObject(DebugObject);
      pLastThread_copy = pLastThread;
    }
  }
  Entry = DebugObject->EventList.Flink;
  if ( Entry == &DebugObject->EventList )       // 空链表
    goto empty_link;
  do
  {
    DebugEvent = (PDEBUG_EVENT)Entry;
    Entry = Entry->Flink;
    Flags = DebugEvent->Flags;
    if ( (Flags & 4) == 0 || DebugEvent->BackoutThread != CurrentThread )
      continue;
    Thread = DebugEvent->Thread;
    if ( v5 < 0 )
    {
      if ( (PDEBUG_EVENT)Entry->Blink != DebugEvent
        || (Blink = DebugEvent->EventList.Blink, (PDEBUG_EVENT)Blink->Flink != DebugEvent) )// 链表完整性判断
      {
check_fail:
        __fastfail(3u);
      }
      Blink->Flink = Entry;
      Entry->Blink = Blink;
      goto LABEL_30;
    }
    if ( (Flags & 0x10) != 0 )
    {
      _InterlockedOr((volatile signed __int32 *)&Thread->___u21, 0x80u);
      Flink = DebugEvent->EventList.Flink;
      if ( (PDEBUG_EVENT)DebugEvent->EventList.Flink->Blink != DebugEvent )
        goto check_fail;
      v15 = DebugEvent->EventList.Blink;
      if ( (PDEBUG_EVENT)v15->Flink != DebugEvent )
        goto check_fail;
      v15->Flink = Flink;
      Flink->Blink = v15;
LABEL_30:
      p_EventList = &p_clear_link->EventList;
      if ( (PVOID *)p_clear_link->EventList.Flink != &clear_link )
        goto check_fail;
      DebugEvent->EventList.Flink = (struct _LIST_ENTRY *)&clear_link;
      DebugEvent->EventList.Blink = p_EventList;
      p_EventList->Flink = &DebugEvent->EventList;
      p_clear_link = DebugEvent;
      goto LABEL_32;
    }
    if ( first )
    {
      DebugEvent->Flags = Flags & 0xFFFFFFFB;
      KeSetEvent(&DebugObject->EventsPresent, 0, 0);// 激活调试器
      first = 0;
    }
    DebugEvent->BackoutThread = 0;
    _InterlockedOr((volatile signed __int32 *)&Thread->___u21, 0x40u);
LABEL_32:
    v18 = DebugEvent->Flags;
    if ( (v18 & 8) != 0 )
    {
      DebugEvent->Flags = v18 & 0xFFFFFFF7;
      ExReleaseRundownProtection(&Thread->RundownProtect);
    }
    CurrentThread = v23;
  }
  while ( Entry != &DebugObject->EventList );
  pLastThread_copy = pLastThread;
empty_link:
  KeReleaseGuardedMutex(Mutex);
  if ( v28 )
    KeReleaseGuardedMutex(&DbgkpProcessDebugPortMutex);
  if ( pLastThread_copy )
    ObfDereferenceObjectWithTag(pLastThread_copy, 0x4F676244u);
  while ( 1 )
  {
    v19 = clear_link;
    if ( clear_link == &clear_link )
      break;
    if ( *((PVOID **)clear_link + 1) != &clear_link )
      goto check_fail;
    v20 = *(_QWORD *)clear_link;
    if ( *(PVOID *)(*(_QWORD *)clear_link + 8LL) != clear_link )
      goto check_fail;
    clear_link = *(PVOID *)clear_link;
    *(_QWORD *)(v20 + 8) = &clear_link;
    DbgkpWakeTarget(v19);
  }
  if ( v5 >= 0 )
    DbgkpMarkProcessPeb((ULONG_PTR)Process);
  return v5;
}

注意看
我们传入的LastThread,他又拿去PsGetNextProcessThread,如果拿到了,那说明这期间你又偷偷创建线程了,拿去重新发假消息

1
2
3
4
5
6
7
8
9
10
11
12
13
NextProcessThread = PsGetNextProcessThread(Process, pLastThread_copy);
if ( !NextProcessThread )
    goto LABEL_11;
Process->DebugPort = 0;                   // 说明又创建了一个线程,再去发假消息
KeReleaseGuardedMutex(&DbgkpProcessDebugPortMutex);
v28 = 0;
ObfDereferenceObjectWithTag(pLastThread_copy, 'OgbD');
v5 = DbgkpPostFakeThreadMessages(Process, DebugObject, NextProcessThread, (PETHREAD *)&Object, &pLastThread);
if ( v5 < 0 )
break;
ObfDereferenceObjectWithTag(Object, 0x4F676244u);
ExAcquireFastMutex(&DbgkpProcessDebugPortMutex);
pLastThread_copy = pLastThread;

终于在这一步,我们将调试对象与被调试进程关联了

1
      Process->DebugPort = DebugObject;         // 设置被调试进程debugport

经过一些杂七杂八的检查,比如检查链表完整性
然后就会激活调试器,让他去收那些假消息

1
KeSetEvent(&DebugObject->EventsPresent, 0, 0);// 激活调试器

然后轮询链表,摘下那些没用的,已读的事件,放入clear_link,让DbgkpWakeTarget处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void DbgkpWakeTarget(PDEBUG_EVENT DebugEvent)
{
  ULONG Flags; // eax
  PETHREAD Thread; // rdi

  Flags = DebugEvent->Flags;
  Thread = DebugEvent->Thread;
  if ( (Flags & 0x20) != 0 )
  {
    PsResumeThread(DebugEvent->Thread, 0);
    Flags = DebugEvent->Flags;
  }
  if ( (Flags & 8) != 0 )
  {
    ExReleaseRundownProtection(&Thread->RundownProtect);
    Flags = DebugEvent->Flags;
  }
  if ( (Flags & 2) != 0 )
    DbgkpFreeDebugEvent(DebugEvent);
  else
    KeSetEvent(&DebugEvent->ContinueEvent, 0, 0);
}

大概就是是否调试对象内存,恢复被调试进程的线程,然后KeSetEvent(&DebugEvent->ContinueEvent, 0, 0);告诉被调试进程的那个线程我处理好了,不用死等
ok先更到这,前面的知识以后再来探索吧(