作者:wzt
原文链接:https://mp.weixin.qq.com/s/08KHfzVltDu3rwZefJ98-Q
NT内核在创建进程时,会将自身插入到nt!PsActiveProcessHead
链表中,它保存的是当前系统中活跃的进程链表。
NTSTATUS
PspCreateProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess OPTIONAL,
IN ULONG Flags,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL,
IN ULONG JobMemberLevel
)
{
PspLockProcessList (CurrentThread);
InsertTailList (&PsActiveProcessHead, &Process->ActiveProcessLinks);
PspUnlockProcessList (CurrentThread);
}
在kd查看下相关的数据结构信息:
0: kd> dt nt!_eprocess
+0x2e8 UniqueProcessId : Ptr64 Void
+0x2f0 ActiveProcessLinks : _LIST_ENTRY
Win32 api就是通过调用nt!NtQueryInformationProcess
函数获取系统的进程列表,所以隐藏进程的一个思路就是将目标进程从nt!PsActiveProcessHead
链表中摘除。
首先看下,如何编写kd脚本,来输出全部的进程列表:
r $t1=$proc;
r @$t2=@$t1;
.while (@$t1 != poi(@$t2+0x2f0)-0x2f0)
{
.printf "%ma\n", @$t2+0x450;
r @$t2=poi(@$t2+0x2f0)-0x2f0
}
PsActiveProcessHead是一个双向循环列表,因此只要知道一个节点的地址,就能循环遍历处所有的节点。
$proc
在kd环境中保存的是当前进程的eprocess地址。
Poi(@$t2+0x2f)
为Process->ActiveProcessLinks
地址,poi函数用于取地址中的值,类似于c的取指针值操作。Poi(@$t2+0x2f)
得到的就是当前节点的下一个节点地址。
那么删除双向链表中的节点,就可以使用如下脚本:
$$ 准备遍历PsActiveProcessHead链表
r @$t1=nt!PsActiveProcessHead;
r @$t2=poi($t1);
.while (@$t2 != @$t1)
{
$$ 判断是否是需要隐藏的进程号
.if (poi(@$t2-0x8) == 0n532)
{
.printf "start hide process %ma(%d)\n", @$t2-0x2f0+0x450,poi(@$t2-0x8) ;
$$ 删除链表节点
eq poi(@$t2)+0x8 poi(@$t2+0x8)
eq poi(@$t2+0x8) poi(@$t2)
.break
}
$$ 获取下一节点
r @$t2=poi(@$t2)
}
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1611/