赞
踩
检测隐藏进程除了众所周知的枚举进程ID之外,还有枚举句柄表的方式。不过今天给大家带来的是第三种方法。
应用层通过接口 C r e a t e P r o c e s s \textcolor{cornflowerblue}{CreateProcess} CreateProcess创建进程,在内部会调用到 K e r n e l b a s e ! C r e a t e P r o c e s s I n t e r n a l \textcolor{orange}{Kernelbase!CreateProcessInternal} Kernelbase!CreateProcessInternal函数,该函数会调用 n t d l l ! N t C r e a t e U s e r P r o c e s s \textcolor{orange}{ntdll!NtCreateUserProcess} ntdll!NtCreateUserProcess转到内核执行创建进程,成功后会向csrss进程发送进程创建的消息。
CreateProcessInternal内部
C s r C l i e n t C a l l S e r v e r \textcolor{cornflowerblue}{CsrClientCallServer} CsrClientCallServer在非csrss进程内是通过LPC向csrss通讯的。在csrss进程内,由 C s r A p i R e q u e s t T h r e a d \textcolor{cornflowerblue}{CsrApiRequestThread} CsrApiRequestThread函数接收并处理,最终由 C s r p C r e a t e P r o c e s s \textcolor{cornflowerblue}{CsrpCreateProcess} CsrpCreateProcess函数负责处理新进程创建事件。
CsrpCreateProcess内部
函数会将进程信息链入一个符号为 C s r R o o t P r o c e s s \textcolor{red}{CsrRootProcess} CsrRootProcess的链表中。链表节点结构如下
typedef struct _CSR_PROCESS { struct _CLIENT_ID ClientId; struct _LIST_ENTRY ListLink; // 指向下一个_CSR_PROCESS struct _LIST_ENTRY ThreadList; // 指向_CSR_THREAD struct _CSR_NT_SESSION NtSession; VOID ClientPort; CHAR ClientViewBase; CHAR ClientViewBounds; VOID ProcessHandle; ULONG SequenceNumber; ULONG Flags; ULONG DebugFlags; ULONG ReferenceCount; ULONG ProcessGroupId; ULONG ProcessGroupSequence; ULONG LastMessageSequence; ULONG NumOutstandingMessages; ULONG ShutdownLevel; ULONG ShutdownFlags; struct _LUID Luid; PVOID ServerDllPerProcessData[1]; } CSR_PROCESS, *PCSR_PROCESS;
对于检测隐藏的进程,我们只需要关注该结构的ClientId和ListLink两个字段就可以了。于是事情就变得很明显了,我们只需要遍历这个双向链表就能得到系统创建的所有进程。
不过这个符号并未导出,我们需要通过特征码去定位。以win10 1909 x64为例
我采用的定位方式是先取得 c s r s r v ! C s r E x e c S e r v e r T h r e a d \textcolor{orange}{csrsrv!CsrExecServerThread} csrsrv!CsrExecServerThread函数地址,因为是导出函数,所以很容易获取地址。然后观察该函数的反汇编代码:
CsrExecServerThread内部
于是特征码为: 48 8 B 0 D C C C C C C C C \textcolor{orange}{48\ 8B\ 0D\ CC\ CC\ CC\ CC} 48 8B 0D CC CC CC CC。其他版本系统方法如是,这里不赘述了。
因为csrss是保护进程,应用层无法读取它的内存数据,所以需要放到内核去做。
VOID EnumCsrssProcessList(PCSR_PROCESS CsrProcessList) { PEPROCESS pProcess = NULL; NTSTATUS ntStatus; PUNICODE_STRING uszProcName; PLIST_ENTRY pListHdr; PLIST_ENTRY pNext; __try { ProbeForRead(CsrProcessList, sizeof(CSR_PROCESS), 1); pListHdr = (PLIST_ENTRY)&CsrProcessList->ListLink; pNext = pListHdr->Blink; while (pListHdr != pNext) { PCSR_PROCESS pCsrProc = CONTAINING_RECORD(pNext, CSR_PROCESS, ListLink); ProbeForRead(pCsrProc, sizeof(CSR_PROCESS), 1); ntStatus = PsLookupProcessByProcessId(pCsrProc->ClientId.UniqueProcess, &pProcess); if (NT_SUCCESS(ntStatus)) { ntStatus = SeLocateProcessImageName(pProcess, &uszProcName); if (NT_SUCCESS(ntStatus)) { DbgPrint("Pid: %x -- %wZ\n",PsGetProcessId(pProcess) ,uszProcName); ExFreePool(uszProcName); } ObDereferenceObject(pProcess); } pNext = pNext->Blink; } } __except (EXCEPTION_EXECUTE_HANDLER) { DbgPrint("[!] An exception occurred! Exception code = %I32x\n", GetExceptionCode()); } }
完整代码请到我的github仓库中查看:https://github.com/singlefreshBird/Rootkit/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。