Icesword 是如何列出隐藏进程

2008/8/13 来源:www.arpun.com 作者:小白

icesword 是通过 PspCidTable 这个表来遍历进程的,  PspCidTable 是一个没有被 ntoskrnl.exe 导出的。 这就涉及到如何定位  

PspCidTable 的问题。 icesword 是通过搜索特征串的方式定位 PspCidTalbe. PspCidTable 是一个 HANDLE_TALBE 结构. 

PsLookupProcessByProcessId 函数中会引用 PspCidTalbe 变量。 icesword 从 PsLookupProcessByProcessId 函数的前几十个字节 

内搜索 PspCidTalbe 变量。 在icesword 里面是不能调试的即使是用 windbg , softice,syser 调试器下断点调试, 也是断不住的。  

当然了你也不能用调试器调试, 因为 icesword.exe 会在一个timer 中不停的重新设置 int 1,int 3 的中断处理函数。 设置成  

windows ntoskrnl.exe 中的缺省处理函数。 即使你用硬件断点寄存器也是不管用的。 那有的人就会说既然设置成 windows ntoskrnl.exe  

中的缺省处理函数就可以使用 windbg 双机调试.icesword 也做了处理,icesword 会通过 KdDebuggerEnabled 变量判断是否允许内核 

调试。 如果允许调试的话. icesword 会调用 KdDisableDebugger 函数禁止内核调试。  

第一部分 

(写的太细了,因为怕被 rootkIT 的作者利用.所以就把第一部分给去掉了.如果需要可以单独和我联系) 

写第二部分 

这里顺便在说两个分析 icesword 中遇到的反调试小陷阱 这里把代码片段列出来, 希望作者原谅 

.text:000xxxF0   mov [ebp+IoControlCode], eax 

.text:000xxxF3   mov eax, [esp+5Ch-6Ch] ; 反调试代码  

.text:000xxxF7   push eax 

.text:000xxxF8   mov eax, [esp+60h-6Ch] 

.text:000xxxFC   pop ebx 

.text:000xxxFD   cmp eax, ebx 

.text:000xxxFF   jz short loc_1240B ; 如果没有被调试则会跳转 

.text:000xxx01   mov eax, 200EDBh 

.text:000xxx06   not eax 

.text:000xxx08   push eax 

.text:000xxx09   pop edi 

.text:000xxx0A   stosd 

.text:000xxxF3   mov eax, [esp+5Ch+6Ch] 当单步执行到这条指令或者在这条指令上设置断点的时候, 因为当调试器在这条指令上弹出的时候会 

用到被调试程序的堆栈来保存 EFLAGS,CS,EIP, (如果 int 1,或 int 3 处理函数用任务门就可以解决这个问题。 )例如 当代码执行到这条指令时 

ESP = 805E4320h   执行完这条指令是 eax 的值为 [ESP+5Ch-6Ch]=[ESP-10h]=[805E4320h-10h]=[805E4310h] 的值。  

当单步执行到 .text:000xxxF8   mov eax, [esp+60h-6Ch] 指令的时候 ESP=805E432Ch 以为其中入栈了一个 eax 所以 ESP=805E432Ch, 

执行完 .text:000xxxF8   mov eax, [esp+60h-6Ch] 条指令的时候 eax = [ESP+60h-6Ch]=[ESP-Ch]=[805E432Ch-Ch]=[805E4310h] 

如果不调试的情况下 读的是同一个地址的值, 所以两个值比较应该是相同的 也就是 .text:000xxxFD   cmp eax, ebx 这条指令的比较结果 

应该是相同的。 这个指令 .text:000xxxFF   jz short loc_1240B 执行后直接跳转到。  

如果是被调试器调试的情况下 .text:000xxxFF   jz short loc_1240B 不会跳转。  如果不跳转时下面的代码 会覆盖掉系统的当前 ETHREAD  

指针。 接下来在调用很多系统函数都会导致系统崩溃, 并且是崩溃到系统模块里面, 这样给你定位错误带来误导。 哈哈 

.text:000xxx68   push 1 ; Alignment 

.text:000xxx6A   push 40h ; Length 

.text:000xxx6C   push CurrentEProcessObject ; Address 

.text:000xxx72   call ds:ProbeForRead 

这里是故意做个异常来实现跳转。 如果你在 .text:000xxx72   call ds:ProbeForRead 指令上单步执行的时候调试器会跑飞了,  

也就是说从调试器退出了, 没有继续跟踪下去。  

第三部分 

接下来说我们的 PspCidTable 我们找到了 PspCidTable 变量后,  PspCidTable [这个 HANDLE_TABLE 的句柄表中, 保存着所有进程和线程对象的指针。  

PID(进程ID)和 ThreadID(线程ID)就是在这个句柄表中的索引。 这个 HANDLE_TABLE 不属于任何进程, 也没有链在 HANDLE_TABLE 链上。 全局变量  

PspCidTable 中是指向这个 HANDLE_TABLE 的指针。 这个 HANDLE_TABLE 还有一点和别的 HANDLE_TABLE 都不同, 就是它的 HANDLE_TABLE_ENTRY 中的 

第一个32bIT 放着的是对象体指针(当然需要转换)而不是对象头指针(对象指针就是对象体指针)。 ] (特别注明 在[]的话不是俺写的是在网上抄来的 

这里特别感谢 “JIURL玩玩Win2k进程线程篇 HANDLE_TABLE” 文章的作者:JIURL ) 

我们之要想到办法遍历这个 PspCidTable 句柄表就可以遍历到系统的所有进程。 icesword 为了遍历这个表他使用了系统为公开的 ntoskrnl.exe 

的导出函数 ExEnumHandleTable 。  

icesword 定位到 ntoskrnl.exe 导出的 ExEnumHandleTable函数。  

这个函数是未公开的函数。   

这个函数的函数原形可能是 VOID STDCALL ExEnumHandleTable (PULONG HandleTable, PVOID Callback, PVOID Param, PHANDLE Handle OPTIONAL); 

其中的参数 PULONG HandleTable 就可以用 PspCidTable 做参数.

PVOID Callback 的类型为 bool (*EXENUMHANDLETABLECALLBACK)(HANDLE_TALBE_ENTRY*,DWORD PID,PVOID Param) 函数指针。

PVOID Param 参数就是传送给回调函数的参数。

PHANDLE Handle OPTIONAL 这个参数俺还没搞懂什么意思。 在说俺也用不到他, 所以也不管他了随他去吧。

当调用 ExEnumHandleTable 函数的时候 函数在每次枚举到表中的一个句柄时都会调用一次回调函数。

当调用的 Callback 回调函数返回值为 0 时继续枚举句柄表, 如果返回 1 时则停止枚举。

网友评论
评论(...
全部评论