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
我们可用看到交叉应用,他被很多关键函数调用,比如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先更到这,前面的知识以后再来探索吧(