这篇我们来看看DbgkpPostFakeThreadMessages函数。
下面看看此函数的汇编代码:
NTSTATUS
DbgkpPostFakeThreadMessages(
ULONG Unkown1, //此参数为寄存器传参(ecx)
PEPROCESS Process,
PDEBUG_OBJECT DebugObject,
ULONG *Unkown2,
PETHREAD *pLastThread
);
820b59af push 0E8h
820b59b4 push offset nt! ?? ::FNODOBFM::`string'+0x74d8 (81e61678)
820b59b9 call nt!_SEH_prolog4 (81e86240)
820b59be mov edi,ecx //DbgkpPostFakeThreadMessages第一个参数
820b59c0 xor esi,esi
820b59c2 mov dword ptr [ebp-28h],esi
820b59c5 mov eax,dword ptr fs:[00000124h]
820b59cb mov dword ptr [ebp-34h],eax //[ebp-0x34h] = 当前线程ethread
820b59ce mov dword ptr [ebp-24h],0C0000001h //[ebp-24h]存放的是错误代码
820b59d5 cmp edi,esi //提供的第一个参数是否为零
820b59d7 je nt!DbgkpPostFakeThreadMessages+0x38 (820b59e7) //是的话跳转
820b59d9 mov byte ptr [ebp-19h],0
820b59dd mov dword ptr [ebp-28h],edi
820b59e0 call nt!ObfReferenceObject (81e80d74) //说明第一个参数是内核对象
820b59e5 jmp nt!DbgkpPostFakeThreadMessages+0x47 (820b59f6) //跳
820b59e7 push esi //esi = 0
820b59e8 mov eax,dword ptr [ebp+8] //Process
820b59eb call nt!PsGetNextProcessThread (8203b449) //获取Process的第一个线程
820b59f0 mov edi,eax //edi = PETHREAD
820b59f2 mov byte ptr [ebp-19h],1
820b59f6 mov dword ptr [ebp-30h],edi //[ebp-0x30] = PETHREAD
820b59f9 test edi,edi
820b59fb je nt!DbgkpPostFakeThreadMessages+0x1c4 (820b5b73) //edi是零的话退出循环
820b5a01 test esi,esi //esi判断不是零的话,就减少引用计数
820b5a03 je nt!DbgkpPostFakeThreadMessages+0x5d (820b5a0c)
820b5a05 mov ecx,esi
820b5a07 call nt!ObfDereferenceObject (81e7f163) //ObfDereferenceObject(esi)
820b5a0c mov dword ptr [ebp-2Ch],edi
820b5a0f mov ecx,edi
820b5a11 call nt!ObfReferenceObject (81e80d74) //增加PsGetNextProcessThread返回线程对象的引用计数
820b5a16 test dword ptr [edi+3Ch],2000h //判断是否是系统线程
820b5a1d jne nt!DbgkpPostFakeThreadMessages+0x29d (820b5c4c) //是系统线程就重新再获取一条线程
820b5a23 lea ebx,[edi+280h]
820b5a29 test byte ptr [ebx],2 //thread->ThreadInserted==0 ?
820b5a2c jne nt!DbgkpPostFakeThreadMessages+0x92 (820b5a41) //不为零跳转
820b5a2e mov esi,dword ptr [ebp-34h] //esi = 当前线程ethread
820b5a31 mov eax,edi //eax = thread
820b5a33 call nt!PsSynchronizeWithThreadInsertion (820e431c) //线程插入同步?不太明白是什么作用
820b5a38 test byte ptr [ebx],2 //如果还是thread->ThreadInserted值没变
820b5a3b je nt!DbgkpPostFakeThreadMessages+0x29d (820b5c4c) //那么我们就重新获取下条线程
820b5a41 lea ecx,[edi+270h]
820b5a47 mov edx,dword ptr [ecx]
820b5a49 and edx,0FFFFFFFEh
820b5a4c lea eax,[edx+2]
820b5a4f mov esi,eax
820b5a51 mov ebx,ecx
820b5a53 mov eax,edx
820b5a55 lock cmpxchg dword ptr [ebx],esi
820b5a59 cmp eax,edx
820b5a5b je nt!DbgkpPostFakeThreadMessages+0xb7 (820b5a66)
820b5a5d call nt!ExfAcquireRundownProtection (81e9fb46)
//820b5a41到820b5a5d是执行ExAcquireRundownProtection函数
820b5a62 test al,al
820b5a64 je nt!DbgkpPostFakeThreadMessages+0xd3 (820b5a82) //ExAcquireRundownProtection失败,就跳
820b5a66 mov dword ptr [ebp-20h],0Ah //这个应该是个标记,在后面还会用到
820b5a6d push 0
820b5a6f push edi
820b5a70 call nt!PsSuspendThread (8209d273) //暂停线程
820b5a75 test eax,eax
820b5a77 jl nt!DbgkpPostFakeThreadMessages+0xda (820b5a89) //没有暂停成功那就跳
820b5a79 mov dword ptr [ebp-20h],2Ah //设置标记
820b5a80 jmp nt!DbgkpPostFakeThreadMessages+0xda (820b5a89) //暂停成功跳
820b5a82 mov dword ptr [ebp-20h],12h //请求线程停止保护失败就设置标记说明
820b5a89 push 0A8h
820b5a8e xor ebx,ebx
820b5a90 push ebx
820b5a91 lea eax,[ebp-0E0h]
820b5a97 push eax
820b5a98 call nt!memset (81e404c0) //清空一片缓冲区,大小是0A8h
820b5a9d add esp,0Ch
//根据下面分析,[ebp-19h] = 1 应该表示是第一次执行PsGetNextProcessThread且PsGetNextProcessThread第二个参数为零,那么这样分析的话,该变量实际就是代表了是否是被调试进程的第一个线程
820b5aa0 cmp byte ptr [ebp-19h],bl
820b5aa3 je nt!DbgkpPostFakeThreadMessages+0x12b (820b5ada) //不是第一个线程的话跳转
820b5aa5 test byte ptr [ebp-20h],10h //分析了发现只有当执行ExAcquireRundownProtection失败才会到达此处
820b5aa9 jne nt!DbgkpPostFakeThreadMessages+0x12b (820b5ada) //ExAcquireRundownProtection失败跳转
820b5aab mov byte ptr [ebp-1Ah],1 //变量设置true
820b5aaf mov dword ptr [ebp-0C8h],2 //这也是一个标记
820b5ab9 mov esi,dword ptr [ebp+8] //esi = Process
820b5abc mov ecx,dword ptr [esi+128h] //Process->SectionObject
820b5ac2 cmp ecx,ebx //是否为零
820b5ac4 je nt!DbgkpPostFakeThreadMessages+0x1ee (820b5b9d) //为零跳转
820b5aca call nt!DbgkpSectionToFileHandle (820b6993) //通过进程可执行内存区对象获得一个模块句柄
820b5acf mov dword ptr [ebp-0BCh],eax //[ebp-0xBC]就是模块句柄
820b5ad5 jmp nt!DbgkpPostFakeThreadMessages+0x1f4 (820b5ba3) //跳
820b5ada mov byte ptr [ebp-1Ah],0 //可能表示不是第一个线程
820b5ade mov dword ptr [ebp-0C8h],1 //改变标记的值
820b5ae8 mov eax,dword ptr [edi+260h] //eax = thread->Win32StartAddress
820b5aee mov dword ptr [ebp-0BCh],eax //这时候[ebp-0BCh]保存了Win32StartAddress
820b5af4 mov esi,dword ptr [ebp+8] //esi = Process
820b5af7 push dword ptr [ebp+0Ch] //DebugObject
820b5afa push dword ptr [ebp-20h]
//这个明显是一个结构,ebp-0E0h到ebp-038h范围都是这个结构的成员
820b5afd lea eax,[ebp-0E0h]
820b5b03 push eax
820b5b04 push edi //线程
820b5b05 push esi //进程
820b5b06 call nt!DbgkpQueueMessage (820b5156) //call DbgkpQueueMessage
820b5b0b mov dword ptr [ebp-24h],eax //保存下返回值
820b5b0e test eax,eax
820b5b10 jge nt!DbgkpPostFakeThreadMessages+0x279 (820b5c28) //成功的话跳
820b5b16 test byte ptr [ebp-20h],20h //看看是否暂停过线程
820b5b1a je nt!DbgkpPostFakeThreadMessages+0x174 (820b5b23) //没有暂停就跳转
820b5b1c mov eax,edi
820b5b1e call nt!KeResumeThread (81ea8dca) //暂停过的话就恢复该线程
820b5b23 test byte ptr [ebp-20h],8 //看看是否申请过停止保护
820b5b27 je nt!DbgkpPostFakeThreadMessages+0x19b (820b5b4a) //没申请过的话就跳转
820b5b29 lea ecx,[edi+270h]
820b5b2f mov edx,dword ptr [ecx]
820b5b31 and edx,0FFFFFFFEh
820b5b34 lea eax,[edx-2]
820b5b37 mov esi,eax
820b5b39 mov ebx,ecx
820b5b3b mov eax,edx
820b5b3d lock cmpxchg dword ptr [ebx],esi
820b5b41 cmp eax,edx
820b5b43 je nt!DbgkpPostFakeThreadMessages+0x19b (820b5b4a)
820b5b45 call nt!ExfReleaseRundownProtection (81e9fc03)
//上面的820b5b29到820b5b45是执行ExReleaseRundownProtection函数
820b5b4a cmp dword ptr [ebp-0C8h],2 //这是个标记,应该表示的是哪种事件,通过分析发现它表示的意义应该是:要是进程刚被附加时,这个值就是2,要是附加后创建的是条线程的话,这个值就是1
820b5b51 jne nt!DbgkpPostFakeThreadMessages+0x1ba (820b5b69) //如果是刚刚被调试的话
//当[ebp-0C8h]是2的时候[ebp-0BCh]代表的是被调试进程可执行模块关联的一个句柄
820b5b53 cmp dword ptr [ebp-0BCh],0
820b5b5a je nt!DbgkpPostFakeThreadMessages+0x1ba (820b5b69) //如果这个句柄值是零,跳转
820b5b5c push 0
820b5b5e push dword ptr [ebp-0BCh]
820b5b64 call nt!ObCloseHandle (82048b62) //句柄值不是零就关闭此句柄
820b5b69 mov ecx,edi
820b5b6b call nt!ObfDereferenceObject (81e7f163) //减少对线程的引用计数
820b5b70 mov esi,dword ptr [ebp-2Ch]
820b5b73 cmp dword ptr [ebp-24h],0 //看看错误代码
820b5b77 jge nt!DbgkpPostFakeThreadMessages+0x2b3 (820b5c62) //没有错误跳转
820b5b7d mov ecx,dword ptr [ebp-28h]
820b5b80 test ecx,ecx
820b5b82 je nt!DbgkpPostFakeThreadMessages+0x1da (820b5b89)
820b5b84 call nt!ObfDereferenceObject (81e7f163) //减少对传入参数的引用
820b5b89 test esi,esi
820b5b8b je nt!DbgkpPostFakeThreadMessages+0x2d8 (820b5c87)
820b5b91 mov ecx,esi
820b5b93 call nt!ObfDereferenceObject (81e7f163) //减少对获取到的线程的引用
820b5b98 jmp nt!DbgkpPostFakeThreadMessages+0x2d8 (820b5c87) //退出
820b5b9d mov dword ptr [ebp-0BCh],ebx //模块句柄为空
820b5ba3 mov eax,dword ptr [esi+12Ch]
820b5ba9 mov dword ptr [ebp-0B8h],eax //[ebp-0B8h] = Process->SectionBaseAddress
820b5baf lea eax,[ebp-0F8h]
820b5bb5 push eax
820b5bb6 push esi
820b5bb7 call nt!KeStackAttachProcess (81ea20ef) //附载到被调试进程
820b5bbc mov dword ptr [ebp-4],ebx
820b5bbf push dword ptr [esi+12Ch]
820b5bc5 call nt!RtlImageNtHeader (81eaed7d) //得到PIMAGE_NT_HEADER
820b5bca cmp eax,ebx
820b5bcc je nt!DbgkpPostFakeThreadMessages+0x237 (820b5be6) //如果没有得到的话跳转
820b5bce mov dword ptr [ebp-0A8h],ebx //这是在上面那个A8大小的结构成员
820b5bd4 mov ecx,dword ptr [eax+0Ch] //image_file_header里面PointerToSymbolTable
820b5bd7 mov dword ptr [ebp-0B4h],ecx //给A8大小的那个结构成员
820b5bdd mov eax,dword ptr [eax+10h] //image_file_header里面NumberOfSymbols
820b5be0 mov dword ptr [ebp-0B0h],eax //给A8大小的那个结构成员
820b5be6 mov dword ptr [ebp-4],0FFFFFFFEh
820b5bed jmp nt!DbgkpPostFakeThreadMessages+0x268 (820b5c17) //跳
820b5bef xor eax,eax
820b5bf1 inc eax
820b5bf2 ret
820b5bf3 mov esp,dword ptr [ebp-18h]
820b5bf6 xor eax,eax
820b5bf8 mov dword ptr [ebp-0A8h],eax
820b5bfe mov dword ptr [ebp-0B4h],eax
820b5c04 mov dword ptr [ebp-0B0h],eax
820b5c0a mov dword ptr [ebp-4],0FFFFFFFEh
820b5c11 mov edi,dword ptr [ebp-30h]
820b5c14 mov esi,dword ptr [ebp+8]
//820b5bef到820b5c14是个异常处理
820b5c17 lea eax,[ebp-0F8h]
820b5c1d push eax
820b5c1e call nt!KeUnstackDetachProcess (81e9d732) //解除附载
820b5c23 jmp nt!DbgkpPostFakeThreadMessages+0x148 (820b5af7)
820b5c28 cmp byte ptr [ebp-1Ah],0
820b5c2c je nt!DbgkpPostFakeThreadMessages+0x29d (820b5c4c)
820b5c2e mov byte ptr [ebp-19h],0
820b5c32 mov ecx,edi
820b5c34 call nt!ObfReferenceObject (81e80d74)
820b5c39 mov dword ptr [ebp-28h],edi
820b5c3c lea eax,[ebp-0E0h]
820b5c42 push eax
820b5c43 push dword ptr [ebp+0Ch]
820b5c46 push edi
820b5c47 call nt!DbgkSendSystemDllMessages (820b5417) //目前不知道它干什么的,等以后慢慢分析
820b5c4c push edi
820b5c4d mov eax,dword ptr [ebp+8]
820b5c50 call nt!PsGetNextProcessThread (8203b449) //获取下一个,实际就是个循环
820b5c55 mov edi,eax
820b5c57 mov dword ptr [ebp-30h],eax
820b5c5a mov esi,dword ptr [ebp-2Ch]
820b5c5d jmp nt!DbgkpPostFakeThreadMessages+0x4a (820b59f9)
820b5c62 mov eax,dword ptr [ebp-28h]
820b5c65 test eax,eax
820b5c67 je nt!DbgkpPostFakeThreadMessages+0x2c6 (820b5c75) //为零的话
820b5c69 mov ecx,dword ptr [ebp+10h]
//*Unkown2 = 一个线程,这个线程应该是FirstThread,这个要在后面写出c代码看起来才方便
820b5c6c mov dword ptr [ecx],eax
820b5c6e mov eax,dword ptr [ebp+14h]
//*pLastThread = LastThread,这个倒是很好理解了
820b5c71 mov dword ptr [eax],esi
820b5c73 jmp nt!DbgkpPostFakeThreadMessages+0x2d8 (820b5c87)
820b5c75 test esi,esi
820b5c77 je nt!DbgkpPostFakeThreadMessages+0x2d1 (820b5c80)
820b5c79 mov ecx,esi
820b5c7b call nt!ObfDereferenceObject (81e7f163) //减少对象引用计数
820b5c80 mov dword ptr [ebp-24h],0C0000001h //设置错误码
820b5c87 mov eax,dword ptr [ebp-24h]
820b5c8a call nt!_SEH_epilog4 (81e86285)
820b5c8f ret 10h
这个函数有些复杂,主要是逻辑判断纵横交错,幸亏有ida的帮助。
汇编代码的注释只是为了自己看而已,我们学习的话最好还是搞成c代码好看些。在弄成c代码之前,我补充下DbgkpPostFakeThreadMessages未知的两个参数,这两个参数通过上面代码可以分析出来大概是什么东西。
NTSTATUS
DbgkpPostFakeThreadMessages(
PETHREAD StartThread, //此参数为寄存器传参(ecx)
PEPROCESS Process,
PDEBUG_OBJECT DebugObject,
PETHREAD *pFirstThread,
PETHREAD *pLastThread
);
上面是完整的声明,那么下面就写出该函数的c代码,首先定义一些有用的结构,方便后续工作。
#define IS_SYSTEM_THREAD(Thread) (((Thread)->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_SYSTEM) != 0)
//枚举类型,指定是哪种事件
typedef enum _DBGKM_APINUMBER {
DbgKmExceptionApi,
DbgKmCreateThreadApi,
DbgKmCreateProcessApi,
DbgKmExitThreadApi,
DbgKmExitProcessApi,
DbgKmLoadDllApi,
DbgKmUnloadDllApi,
DbgKmMaxApiNumber
} DBGKM_APINUMBER;
//异常消息
typedef struct _DBGKM_EXCEPTION {
EXCEPTION_RECORD ExceptionRecord;
ULONG FirstChance;
} DBGKM_EXCEPTION, *PDBGKM_EXCEPTION;
//创建线程消息
typedef struct _DBGKM_CREATE_THREAD {
ULONG SubSystemKey;
PVOID StartAddress;
} DBGKM_CREATE_THREAD, *PDBGKM_CREATE_THREAD;
//创建进程消息
typedef struct _DBGKM_CREATE_PROCESS {
ULONG SubSystemKey;
HANDLE FileHandle;
PVOID BaseOfImage;
ULONG DebugInfoFileOffset;
ULONG DebugInfoSize;
DBGKM_CREATE_THREAD InitialThread;
} DBGKM_CREATE_PROCESS, *PDBGKM_CREATE_PROCESS;
//退出线程消息
typedef struct _DBGKM_EXIT_THREAD {
NTSTATUS ExitStatus;
} DBGKM_EXIT_THREAD, *PDBGKM_EXIT_THREAD;
//退出进程消息
typedef struct _DBGKM_EXIT_PROCESS {
NTSTATUS ExitStatus;
} DBGKM_EXIT_PROCESS, *PDBGKM_EXIT_PROCESS;
//加载模块消息
typedef struct _DBGKM_LOAD_DLL {
HANDLE FileHandle;
PVOID BaseOfDll;
ULONG DebugInfoFileOffset;
ULONG DebugInfoSize;
} DBGKM_LOAD_DLL, *PDBGKM_LOAD_DLL;
//卸载模块消息
typedef struct _DBGKM_UNLOAD_DLL {
PVOID BaseAddress;
} DBGKM_UNLOAD_DLL, *PDBGKM_UNLOAD_DLL;
//PORT_MESSAGE结构
typedef struct _PORT_MESSAGE
{
ULONG u1;
ULONG u2;
union
{
CLIENT_ID ClientId;
Float DoNotUseThisField;
};
ULONG MessageId;
union
{
ULONG ClientViewSize;
ULONG CallbackId;
};
} PORT_MESSAGE, *PPORT_MESSAGE;
//消息结构
typedef struct _DBGKM_APIMSG {
PORT_MESSAGE h; //+0x0
DBGKM_APINUMBER ApiNumber; //+0x18
NTSTATUS ReturnedStatus; //+0x1c
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; //0x20
} DBGKM_APIMSG, *PDBGKM_APIMSG;
以上结构除PORT_MESSAGE外基本出自2k系统源码,可能有很大出入,但是这些结构比较复杂(联合太多,分析很有难度),所以我找个现成的。分析了下xp发现了它的DBGKM_APIMSG也是同样的大小,而且看起来里面的成员结构也没改变。可是这个结构明显没有A8大小,既然和xp一样那我就从ReactOS源码中找相关定义。惊奇的是,ReactOS里面居然也是这样的定义......看来问题只能在后面慢慢揭晓。
NTSTATUS
DbgkpPostFakeThreadMessages(
PETHREAD StartThread, //此参数为寄存器传参(ecx)
PEPROCESS Process,
PDEBUG_OBJECT DebugObject,
PETHREAD *pFirstThread,
PETHREAD *pLastThread
)
{
NTSTATUS Status;
PETHREAD Thread, FirstThread, LastThread, CurrentThread;
DBGKM_APIMSG ApiMsg; //上面分析的一个未知的结构体,应该就是DBGKM_APIMSG类型的结构
BOOLEAN First = TRUE;
BOOLEAN IsFirstThread;
PIMAGE_NT_HEADERS NtHeaders;
ULONG Flags;
NTSTATUS Status;
KAPC_STATE ApcState;
Status = STATUS_UNSUCCESSFUL;
CurrentThread = PsGetCurrentThread();
if(StartThread==0)
{
StartThread = PsGetNextProcessThread(Process,0);
First = TRUE;
}else{
First = FALSE;
FirstThread = StartThread;
ObfReferenceObject(StartThread);
}
for( Thread = StartThread;
Thread != NULL;
Thread = PsGetNextProcessThread (Process, Thread))
{
if(LastThread!=0)
{
ObfDereferenceObject(LastThread);
}
LastThread = Thread;
ObfReferenceObject(LastThread);
if(IS_SYSTEM_THREAD(Thread))
{ continue; }
if(Thread->ThreadInserted==0)
{
PsSynchronizeWithThreadInsertion(Thread,CurrentThread);
if(thread->ThreadInserted==0)
{ continue; }
}
if(ExAcquireRundownProtection (&Thread->RundownProtect))
{
Flags = 0xA;
Status = PsSuspendThread(Thread,0);
if(NT_SUCCESS(Status))
{
Flags = 0x2A;
}
}else{
Flags = 0x12;
}
//每次构造一个DBGKM_APIMSG结构
memset(&ApiMsg,0,sizeof(DBGKM_APIMSG));
if(First && (Flags&0x10==0))
{
//进程的第一个线程才会到这里
IsFirstThread = TURE;
ApiMsg.ApiNumber = DbgKmCreateProcessApi;
if(Process->SectionObject)
{
//DbgkpSectionToFileHandle函数是返回一个模块的句柄
ApiMsg.u.CreateProcessInfo.FileHandle = DbgkpSectionToFileHandle(Process->SectionObject);
}else{
ApiMsg.u.CreateProcessInfo.FileHandle = NULL;
}
ApiMsg.u.CreateProcessInfo.BaseOfImage = Process->SectionBaseAddress;
KeStackAttachProcess(Process,&ApcState);
__try{
NtHeaders = RtlImageNtHeader(Process->SectionBaseAddress);
if(NtHeaders)
{
ApiMsg.u.CreateProcessInfo.InitialThread.StartAddress = NULL;
ApiMsg.u.CreateProcessInfo.DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
ApiMsg.u.CreateProcessInfo.DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
}
}except(EXCEPTION_EXECUTE_HANDLER){
ApiMsg.u.CreateProcessInfo.InitialThread.StartAddress = NULL;
ApiMsg.u.CreateProcessInfo.DebugInfoFileOffset = 0;
ApiMsg.u.CreateProcessInfo.DebugInfoSize = 0;
}
KeUnstackDetachProcess(&ApcState);
}else{
IsFirstThread = FALSE;
ApiMsg.ApiNumber = DbgKmCreateThreadApi;
ApiMsg.u.CreateThread.StartAddress = Thread->StartAddress;
}
Status = DbgkpQueueMessage ( Process,
Thread,
&ApiMsg,
Flags,
DebugObject);
if(!NT_SUCCESS(Status))
{
if(Flags & 0x20)
{
KeResumeThread(Thread);
}
if(Flags & 0x8)
{
ExReleaseRundownProtection(&Thread->RundownProtect);
}
if(ApiMsg.ApiNumber == DbgKmCreateProcessApi && ApiMsg.u.CreateProcessInfo.FileHandle != NULL)
{
ObCloseHandle (ApiMsg.u.CreateProcessInfo.FileHandle, KernelMode);
}
ObfDereferenceObject(Thread);
break;
}else if(IsFirstThread){
First = FALSE;
ObReferenceObject (Thread);
FirstThread = Thread;
DbgkSendSystemDllMessages(Thread,DebugObject,&ApiMsg);
}
}
if (!NT_SUCCESS (Status)) {
if (FirstThread)
{
ObDereferenceObject (FirstThread);
}
if (LastThread != NULL)
{
ObDereferenceObject (LastThread);
}
} else {
if (FirstThread) {
*pFirstThread = FirstThread;
*pLastThread = LastThread;
} else {
if (LastThread != NULL)
{
ObDereferenceObject (LastThread);
}
Status = STATUS_UNSUCCESSFUL;
}
}
return Status;
}
这个函数的逻辑有点多,但做的事情不是很多,总结下它做了哪几件事:
1,设置每个被调试进程为暂停状态和申请线程停止保护。
2,为每个线程调用DbgkpQueueMessage函数,如果该函数调用失败则做退出工作。
3,如果是创建一个进程的话,当得到第一个线程时,要调用DbgkSendSystemDllMessages函数。
还有其他工作若干,只是显得不太重要所以也懒得总结了。实际这个函数主要就干两件事情——暂停被调试进程的线程并且为每个线程调用DbgkpQueueMessage函数。关于暂停线程十分好理解,那么为什么要调用DbgkpQueueMessage函数呢?这个要等分析完该函数才知道答案。
注意此结构中涉及到一个DBGKM_APIMSG结构,这个结构相当重要。我目前还不敢确定上面对这个结构的定义是正确的,只是现在分析的太少,等后面慢慢分析多点就大概知道是做什么的了,这里只能说明它可能是表示一个消息种类和消息携带的信息。
函数中有调用到三个未知函数:
1,DbgkpSectionToFileHandle;
2,DbgkSendSystemDllMessages;
3,DbgkpQueueMessage.
前两个为辅助函数,第三个才是重点。后一篇以介绍第三个函数为主,但是前两个函数在恰当的时候我就会分析出来的。
打个广告,本人创建的编程交流论坛:梦织未来(www.mengwuji.net)
希望大家多多支持一下!