前言
前几篇我们分析了windows的调试体系,但是使用的例子是附加调试的,但是创建调试有着些许不同
CreateProcessW
我们来看一个创建进程的函数
1
2
3
4
5
6
7
8
9
10
11
BOOL __stdcall CreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
在使用该函数时,我们可以填写dwCreationFlags的部分位,使进程在创建时便会被我们调试
1
CreateProcessW(..., dwCreationFlags = DEBUG_ONLY_THIS_PROCESS | CREATE_SUSPENDED, ...);
标志 值 调试含义
DEBUG_PROCESS 0x1 新进程要被调试,且子进程递归继承
DEBUG_ONLY_THIS_PROCESS 0x2 仅调试新进程本身,子进程不继承
CREATE_SUSPENDED 0x4 线程创建即挂起,调试器先拿句柄后设断点
同时lpProcessInformation里我们还可以拿到进程的线程与进程句柄
这究竟是怎么样的一套流程,让我们深入内核分析
CreateProcessInternalW
在kernelbase里,我们看到CreateProcessW只是一层薄包装,之后便深入CreateProcessInternalW
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
BOOL __stdcall CreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
return CreateProcessInternalW(
0,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation,
0);
}
CreateProcessInternalW的代码比较长,我们就看调试相关部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if ( (maskedCreateFlags & 3) != 0 )
{
dbgStatus = DbgUiConnectToDbg(); // 连接到调试器
if ( dbgStatus < 0 )
{
errorStatus = (unsigned int)dbgStatus;
goto LABEL_706;
}
hThreadDebugObject = DbgUiGetThreadDebugObject(); //获取调试句柄
hDebugObject = hThreadDebugObject;
ntCreateFlags = ntFlagTmp3;
if ( (win32CreateFlags & 2) != 0 )
ntCreateFlags = ntFlagTmp3 | 2;
}
这里可以看到,如果某个位被置位了,就会调用DbgUiConnectToDbg,而且现在仍然处于创建者的进程上下文中,根据之前的逆向结果,这一步是会创建调试对象,并且将调试对象先挂到调试器上 结果一大堆的处理然后调用NtCreateUserProcess,进入内核
1
v39 = NtCreateUserProcess(&hProcess, &hThread, 0x2000000, 0x2000000);// 进入内核
该函数返回时会回写hProcess,hThread,最终由CreateProcessInternalW返回
1
2
3
4
5
6
7
else
{
procInfo->hProcess = hProcess;
}
v65->hThread = hThread;
v65->dwProcessId = v312.m128i_i32[0];
v65->dwThreadId = v312.m128i_u32[2];
NtCreateUserProcess
NtCreateUserProcess在ntdll里就是简单的syscall,我们直接看ntoskrnl里的,代码很长,我们直接来看调试相关的
PspBuildCreateProcessContext
1
2
3
4
5
6
7
if ( !AttributeList
|| (result = PspBuildCreateProcessContext(
(unsigned __int64 *)AttributeList,
PreviousMode,
0,
(PS_CREATE_INFO *)LocalCreateInfo),
result >= 0) )
这里调用了PspBuildCreateProcessContext,我们只看关键部分
1
2
3
4
5
6
isDebugObject = isParentProcAttr - 1;
if ( isDebugObject )
...
if ( pAttrEntry[1] != 8 )
goto LABEL_125;
CreateInfo->InitParameter.DebugPort = (HANDLE)pAttrEntry[2];
这个函数其实就是一个信息处理函数,把我们传入属性里的调试对象句柄放入CreateInfo的InitParameter.DebugPort里面
PspInsertProcess
第二处就是PspInsertProcess,这是最关键的一部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
inserted = PspInsertProcess(
(PEPROCESS)v76,
ParentProcess,
v54,
ProcessFlags,
*(HANDLE *)&LocalCreateInfo[136], //DebugObjectHandle
PriorityHint[4],
v56,
(PACCESS_STATE)AccessState);
// 定义
NTSTATUS PspInsertProcess(
PEPROCESS CurrentProcess,
PEPROCESS ParentProcess,
ACCESS_MASK DesiredAccess,
ULONG Flags,
HANDLE DebugObjectHandle,
char PriorityHint,
__int64 a7,
PACCESS_STATE AccessState)
PspInsertProcess里面最关键的一部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if ( (Process->Flags & 8) != 0 )
{
status = 0xC000010A;
}
else if ( !DebugObjectHandle
|| (DebugObject = 0,
v24 = ObReferenceObjectByHandle(
DebugObjectHandle,
2u,
DbgkDebugObjectType,
KeGetCurrentThread()->PreviousMode,
&DebugObject,
0),
pDebugObject = (struct _DEBUG_OBJECT *)DebugObject,
status = v24,
v24 >= 0) ) // PspInsertProcess: Handle 参数就是调试对象句柄(DebugPort). 无句柄则继承父进程 DebugPort; 有则 ObReferenceObjectByHandle(DbgkDebugObjectType) + DbgkCopyProcessDebugPort 挂载
{
status = DbgkCopyProcessDebugPort(CurrentProcess, Process, pDebugObject, &SetDebugFlag);
if ( pDebugObject )
HalPutDmaAdapter((PADAPTER_OBJECT)pDebugObject);
if ( status >= 0 )
{
if ( SetDebugFlag && (v13 & 2) != 0 )
_InterlockedOr((volatile signed __int32 *)&CurrentProcess->___u6, 2u);
这里调用了DbgkCopyProcessDebugPort
DbgkCopyProcessDebugPort
这个函数不长,我们直接看
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
NTSTATUS DbgkCopyProcessDebugPort(
PEPROCESS NewProcess,
PEPROCESS ParentProcess,
PDEBUG_OBJECT DebugObject,
BOOLEAN *SetDebugFlag)
{
PDEBUG_OBJECT IN_DebugObject; // rbx
void *DebugPort; // rbx
bool v9; // zf
__int64 v11; // rcx
char *v12; // r14
NTSTATUS v13; // edi
_EWOW64PROCESS *WoW64Process; // rax
unsigned __int16 Machine; // cx
unsigned __int64 SecureHandle; // rdi
__int64 v17; // rcx
char v18; // di
char *v19; // rbx
_QWORD v20[14]; // [rsp+20h] [rbp-B8h] BYREF
NewProcess->DebugPort = 0;
IN_DebugObject = DebugObject;
if ( DebugObject )
{
ObfReferenceObject(DebugObject);
}
else
{
DebugPort = ParentProcess->DebugPort;
v9 = DebugPort == 0;
if ( !DebugPort )
{
LABEL_3:
*SetDebugFlag = !v9;
return 0;
}
ExAcquireFastMutex(&DbgkpProcessDebugPortMutex);
IN_DebugObject = (PDEBUG_OBJECT)ParentProcess->DebugPort;
if ( IN_DebugObject )
{
if ( (ParentProcess->Flags & 2) != 0 )
IN_DebugObject = 0;
else
ObfReferenceObject(ParentProcess->DebugPort);
}
KeReleaseGuardedMutex(&DbgkpProcessDebugPortMutex);
}
v12 = (char *)IN_DebugObject;
v9 = IN_DebugObject == 0;
if ( !IN_DebugObject )
goto LABEL_3;
LOBYTE(v11) = KeGetCurrentThread()->PreviousMode;
if ( (unsigned __int8)PsTestProtectedProcessIncompatibility(v11, ParentProcess, NewProcess) )
{
v13 = -1073740014;
}
else if ( (IN_DebugObject->Flags & 4) == 0
|| (WoW64Process = NewProcess->WoW64Process) != 0
&& ((Machine = WoW64Process->Machine, Machine == 332) || Machine == 452) )
{
SecureHandle = NewProcess->Pcb.SecureState.SecureHandle;
if ( (SecureHandle & 1) == 0
|| (memset(v20, 0, 0x68u),
v20[1] = SecureHandle,
v20[2] = 1,
LOBYTE(v17) = 2,
v13 = VslpEnterIumSecureMode(v17, 12, 0, v20),
v13 >= 0) )
{
v18 = 0;
ExAcquireFastMutex(&IN_DebugObject->Mutex);
if ( (IN_DebugObject->Flags & 1) != 0 )
v18 = 1;
else
NewProcess->DebugPort = IN_DebugObject; // DBGKOID!! EPROCESS+1400 (BugCheckParameter1[175]) = DebugPort 字段 ← 调试对象正式挂到新进程
KeReleaseGuardedMutex(&IN_DebugObject->Mutex);
if ( v18 )
HalPutDmaAdapter((PADAPTER_OBJECT)IN_DebugObject);
v19 = 0;
if ( !v18 )
v19 = v12;
v9 = v19 == 0;
if ( v19 )
{
DbgkpMarkProcessPeb((ULONG_PTR)NewProcess);
v9 = v19 == 0;
}
goto LABEL_3;
}
}
else
{
v13 = -1073741637;
}
HalPutDmaAdapter((PADAPTER_OBJECT)IN_DebugObject);
return v13;
}
可以看到这一步就是将调试对象挂上被调试进程的部分,同时还还有一个有意思的地方
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
void __fastcall DbgkpMarkProcessPeb(PEPROCESS Process)
{
struct _EX_RUNDOWN_REF *p_RundownProtect; // rdi
_EWOW64PROCESS *pSecureProcessInfo; // rax
unsigned __int16 Machine; // cx
_OWORD ApcFrame[3]; // [rsp+28h] [rbp-40h] BYREF
memset(ApcFrame, 0, sizeof(ApcFrame));
p_RundownProtect = &Process->RundownProtect;
if ( ExAcquireRundownProtection(&Process->RundownProtect) )
{
if ( Process->Peb )
{
KiStackAttachProcess(&Process->Pcb, 0, (__int64)ApcFrame);
ExAcquireFastMutex(&DbgkpProcessDebugPortMutex);
Process->Peb->BeingDebugged = Process->DebugPort != 0;// PEB+2 (BeingDebugged) = (DebugPort != 0),进程内 IsDebuggerPresent 检测的就是这个
pSecureProcessInfo = Process->WoW64Process;
if ( pSecureProcessInfo )
{
Machine = pSecureProcessInfo->Machine;
if ( Machine == 332 || Machine == 452 )
{
if ( pSecureProcessInfo->Peb )
*((_BYTE *)pSecureProcessInfo->Peb + 2) = Process->Peb->BeingDebugged;
}
}
KeReleaseGuardedMutex(&DbgkpProcessDebugPortMutex);
KiUnstackDetachProcess(ApcFrame, 0);
}
ExReleaseRundownProtection(p_RundownProtect);
}
}
BeingDebugged就是这里填上的
PspInsertThread
第三处相关的便是PspInsertThread,此时就要创建一个有效的主线程了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
status = PspInsertThread(
(PETHREAD)DmaAdapter,
(PEPROCESS)v76,
SecurityContext,
(ULONG)PriorityHint,
v55,
v49,
LocalCreateInfo,
0,
(PACCESS_STATE)v109,
OUT_ThreadHandle,
*(PCLIENT_ID *)&LocalCreateInfo[16]);
先看PspInsertThread函数的其中一处
1
2
3
4
5
6
7
if ( (*v41 & 1) != 0 ) // CREATE_SUSPENDED 置位
{
KeSuspendThread((__int64)Thread);
if ( (Thread->CrossThreadFlags & 1) != 0 )
KeForceResumeThread(Thread);
v23 = v41;
}
是不是有点印象,x64dbg里有的那一个创建线程时暂停就是这里,此时该线程不会被cpu调度到,那我们怎么恢复呢?
别忘了我们前面传出的线程句柄哦,通过那个可以恢复
顺带一提线程句柄也是他传出的
1
*(_QWORD *)ThreadHandle = AccessState[2].AuxData;// 传出线程句柄
然后NtCreateUserProcess创建好线程,插入线程队列这个函数就自然而然的返回了,没有阻塞,啥都木有
奇怪了,不是应该要被调试器接管吗?
其实,此时的线程还没有真的跑起来,他只是入队列,还没有拥有自己的上下文被第一次被cpu执行,当第一次cpu调度他时,会在这个独立的上下文下执行PspUserThreadStartup函数
PspUserThreadStartup
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
NTSTATUS PspUserThreadStartup()
{
struct _KTHREAD *CurrentThread; // rsi
__int64 v1; // rcx
__int64 v2; // r8
PEPROCESS Process; // r14
int SessionLocaleId; // eax
__int64 v5; // rdx
NTSTATUS result; // eax
struct _KPRCB *v7; // rdi
ULONG LowPart; // ebx
int v9; // r8d
unsigned __int64 v10; // rax
struct _KPRCB *CurrentPrcb; // rcx
_DWORD *SchedulerAssist; // rdx
bool v13; // zf
unsigned int v14; // eax
__int64 v15; // r8
_QWORD v16[4]; // [rsp+30h] [rbp-B8h] BYREF
_BYTE v17[112]; // [rsp+50h] [rbp-98h] BYREF
v16[0] = 0;
if ( KiIrqlFlags )
{
if ( (KiIrqlFlags & 1) != 0 && (unsigned __int8)(KeGetCurrentIrql() - 2) <= 0xDu )
{
CurrentPrcb = KeGetCurrentPrcb();
SchedulerAssist = CurrentPrcb->SchedulerAssist;
v13 = (SchedulerAssist[5] & 0xFFFF0001) == 0;
SchedulerAssist[5] &= 0xFFFF0001;
if ( v13 )
KiRemoveSystemWorkPriorityKick(CurrentPrcb);
}
}
__writecr8(0);
CurrentThread = KeGetCurrentThread();
v16[2] = CurrentThread;
PspDisablePrimaryTokenExchange(CurrentThread);
if ( (*(_DWORD *)(&CurrentThread[1].SwapListEntry + 1) & 2) == 0 )// 有效性检查
{
LOBYTE(v2) = 1;
PspTerminateThreadByPointer(CurrentThread, 3221225547LL, v2);
}
Process = (PEPROCESS)CurrentThread->ApcState.Process;// 创建的新进程 EPROCESS
v16[1] = Process;
if ( (Process->Flags3 & 1) != 0 ) // Minimal进程
{
DbgkCreateMinimalThread(CurrentThread);
}
else
{
SessionLocaleId = MmGetSessionLocaleId(v1, CurrentThread->Teb);
*(_DWORD *)(v5 + 264) = SessionLocaleId;
PspWriteTebIdealProcessor((__int64)CurrentThread, (__int64)CurrentThread);
DbgkCreateThread((PETHREAD)CurrentThread);
if ( (Process->Flags & 0x80000) == 0
&& !_interlockedbittestandset((volatile signed __int32 *)&Process->___u6, 0x13u) )
{
PfProcessCreateNotification(Process, Process->SectionObject);
}
}
while ( !MEMORY[0xFFFFF78000000330] )
{
KeQuerySystemTimePrecise(v16);
v7 = KeGetCurrentPrcb();
LowPart = KeQueryPerformanceCounter(0).LowPart;
v9 = ExGenRandom(1);
v10 = __rdtsc();
_InterlockedCompareExchange(
(volatile signed __int32 *)0xFFFFF78000000330LL,
LODWORD(v16[0])
^ HIDWORD(v16[0])
^ LowPart
^ v10
^ v9
^ v7->MmPageFaultCount
^ v7->InterruptCount
^ v7->InterruptTime,
0);
}
if ( (Process->Pcb.SecureState.SecureHandle & 1) != 0 )
{
*((_DWORD *)&CurrentThread[1].SwapListEntry + 3) |= 0x200u;
memset(v17, 0, 0x68u);
v14 = VslpEnterIumSecureMode(0, 0, KeGetCurrentThread()->SecureThreadCookie, v17);
LOBYTE(v15) = 1;
return PspTerminateThreadByPointer(CurrentThread, v14, v15);
}
else if ( (*(_DWORD *)(&CurrentThread[1].SwapListEntry + 1) & 1) != 0 )
{
return KeWaitForSingleObject(CurrentThread, UserRequest, 1, 0, 0);
}
else
{
result = Process->Flags3;
if ( (result & 1) == 0 )
return PspInitializeThunkContext();
}
return result;
}
其中会无论怎样都会执行一个函数 – DbgkCreateThread,这个函数就是第一次被调试器正式接管的关键
DbgkCreateThread
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
void DbgkCreateThread(PETHREAD Thread)
{
struct _EPROCESS *Process; // rdi
_EWOW64PROCESS *WoW64Process; // rax
signed __int32 v4; // eax
char v5; // r12
PIMAGE_NT_HEADERS v6; // rax
int i; // esi
__int64 SystemDllInfo; // rax
__int64 v9; // rdx
__int64 v10; // r15
PIMAGE_NT_HEADERS v11; // rax
__int64 v12; // r13
__int64 v13; // rax
struct _DMA_ADAPTER *v14; // rax
unsigned __int16 Machine; // ax
PIMAGE_NT_HEADERS v16; // rax
bool v17; // [rsp+20h] [rbp-1B8h]
PADAPTER_OBJECT DmaAdapter; // [rsp+28h] [rbp-1B0h] BYREF
signed __int32 v19; // [rsp+30h] [rbp-1A8h]
struct _EPROCESS *v20; // [rsp+38h] [rbp-1A0h]
PETHREAD v21; // [rsp+40h] [rbp-198h]
__int128 v22; // [rsp+48h] [rbp-190h] BYREF
__int128 v23; // [rsp+58h] [rbp-180h]
__int128 v24; // [rsp+68h] [rbp-170h]
__int64 v25; // [rsp+78h] [rbp-160h]
__int64 v26; // [rsp+80h] [rbp-158h]
DBGKM_APIMSG APIMSG; // [rsp+90h] [rbp-148h] BYREF
v21 = Thread;
memset(&APIMSG, 0, 0x110u);
Process = (struct _EPROCESS *)Thread->Tcb.ApcState.Process;
v20 = Process;
WoW64Process = Process->WoW64Process;
v17 = 0;
if ( WoW64Process )
{
Machine = WoW64Process->Machine;
if ( Machine == 332 || Machine == 452 )
v17 = 1;
}
_m_prefetchw(&Process->___u6);
v4 = _InterlockedOr((volatile signed __int32 *)&Process->___u6, 0x400001u); //PsProcessIsFirstResume
v5 = v4;
v19 = v4;
if ( (v4 & 0x400000) == 0 && ((PspNotifyEnableMask & 1) != 0 || (PerfGlobalGroupMask & 4) != 0) )
{
v22 = 0;
v23 = 0;
v24 = 0;
v25 = 0;
DmaAdapter = 0;
BYTE8(v22) = 3;
*(_QWORD *)&v23 = Process->SectionBaseAddress;
*(_QWORD *)&v24 = 0;
v6 = RtlImageNtHeader((PVOID)v23);
if ( v6 )
*(_QWORD *)&v24 = v6->OptionalHeader.SizeOfImage;
DWORD2(v23) = 0;
DWORD2(v24) = 0;
PsReferenceProcessFilePointer(Process, &DmaAdapter);
PsCallImageNotifyRoutines(Process->SeAuditProcessCreationInfo.ImageFileName, Process, &v22, DmaAdapter);
HalPutDmaAdapter(DmaAdapter);
for ( i = 0; ; ++i )
{
LODWORD(DmaAdapter) = i;
if ( i >= 6 )
break;
SystemDllInfo = PsQuerySystemDllInfo((unsigned int)i);
v10 = SystemDllInfo;
v26 = SystemDllInfo;
if ( SystemDllInfo
&& (i <= 0
|| *(_WORD *)(SystemDllInfo + 2)
&& Process->WoW64Process
&& i == (unsigned int)PsWow64GetProcessNtdllType(Process, v9)) )
{
DWORD2(v22) = 3;
*(_QWORD *)&v23 = *(_QWORD *)(v10 + 24);
*(_QWORD *)&v24 = 0;
v11 = RtlImageNtHeader(*(PVOID *)(v10 + 24));
if ( v11 )
*(_QWORD *)&v24 = v11->OptionalHeader.SizeOfImage;
DWORD2(v23) = 0;
DWORD2(v24) = 0;
v12 = PspReferenceSystemDll(v10 - 16);
v13 = MiSectionControlArea(v12);
v14 = (struct _DMA_ADAPTER *)MiReferenceControlAreaFile(v13);
DmaAdapter = v14;
if ( v12 )
{
ObFastDereferenceObject(v10 - 16, v12);
v14 = DmaAdapter;
}
PsCallImageNotifyRoutines(v10 + 8, Process, &v22, v14);
HalPutDmaAdapter(DmaAdapter);
}
}
}
if ( Process->DebugPort )
{
if ( (v5 & 1) != 0 )
{
if ( (Thread->CrossThreadFlags & 4) == 0 ) //未被HideFromDebugger置位
{
memset(&APIMSG, 0, 0x40u);
APIMSG.u.Exception.ExceptionRecord.ExceptionRecord = (_EXCEPTION_RECORD *)Thread->Win32StartAddress;
APIMSG.h.u1.Length = 0x400018;
APIMSG.h.u2.ZeroInit = 8;
APIMSG.ApiNumber = DbgKmCreateThreadApi; //投递DBGKM_MSG_CREATE_THREAD
DbgkpSendApiMessage(Process, 1, &APIMSG);
}
}
else
{
memset(&APIMSG, 0, 0x60u);
APIMSG.u.Exception.ExceptionRecord.ExceptionRecord = (_EXCEPTION_RECORD *)DbgkpSectionToFileHandle(Process->SectionObject);
*((_OWORD *)&APIMSG.u.UnloadDll + 1) = (unsigned __int64)Process->SectionBaseAddress;
APIMSG.u.Exception.ExceptionRecord.ExceptionInformation[1] = 0;
v16 = RtlImageNtHeader(Process->SectionBaseAddress);
if ( v16 )
{
if ( v17 )
APIMSG.u.Exception.ExceptionRecord.ExceptionInformation[1] = v16->OptionalHeader.AddressOfEntryPoint
+ HIDWORD(v16->OptionalHeader.ImageBase);
else
APIMSG.u.Exception.ExceptionRecord.ExceptionInformation[1] = v16->OptionalHeader.ImageBase
+ v16->OptionalHeader.AddressOfEntryPoint;
APIMSG.u.LoadDll.NamePointer = *(PVOID *)&v16->FileHeader.PointerToSymbolTable;
}
APIMSG.h.u1.Length = 6291512;
APIMSG.h.u2.ZeroInit = 8;
APIMSG.ApiNumber = DbgKmCreateProcessApi;
DbgkpSendApiMessage(Process, 0, &APIMSG);
if ( APIMSG.u.Exception.ExceptionRecord.ExceptionRecord )
ObCloseHandle(APIMSG.u.Exception.ExceptionRecord.ExceptionRecord, 0);
DbgkSendSystemDllMessages(0, 0, &APIMSG);
}
if ( (Thread->SameThreadPassiveFlags & 0x10) != 0 )
DbgkpPostModuleMessages(Process, Thread, 0);
}
}
他会实现判断是否位第一次启动
1
2
3
4
v4 = _InterlockedOr((volatile signed __int32 *)&Process->___u6, 0x400001u); //PsProcessIsFirstResume
v5 = v4;
...
if ( (v5 & 1) != 0 )
然后判断是否有调试对象,如果有但是非第一次启动,就只投递DBGKM_MSG_CREATE_THREAD
如果是,就发送DbgKmCreateProcessApi
自此,调试器第一次接管被调试进程