内核级进程遍历
Posted bcbobo21cn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核级进程遍历相关的知识,希望对你有一定的参考价值。
原理
windows中,每个进程都有一个属于自己的EPROCESS结构,这个结构中包含了本程序的基本信息,并且数据中存在进程链表,通过该进程链表(双向链表)可以找到其他进程的EPROCESS 结构,所以可以借此遍历系统中的进程。
使用windbg 可以看到eprocess 的结构体,
lkd> dt _eprocess -r1
nt!_EPROCESS
...
+0x084 UniqueProcessId : Ptr32 Void PID
+0x088 ActiveProcessLinks : _LIST_ENTRY 活动进程链表(双向链表)
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
...
+0x174 ImageFileName : [16] UChar //进程名
...
...
...
+0x258 Cookie : Uint4B
demo
用的vs2008sp1 on xp sp3,visual ddk。
其中工程选项中使用了visual studio compiler,而没有用ddk compiler,即使这样,用默认的结构去生成解决方案,生成的sys还是无法加载。于是全删掉框架代码,自己写,好在有ddk的sdk可以用vax智能提示。注意生成debug(chunk)版,否则debugview 无法显示输出。
#include "stdafx.h"
VOID OnUnload(IN PDRIVER_OBJECT pDriverObject)
KdPrint(("OnUnload called"));
NTSTATUS enum_services()
PEPROCESS pEprocess = NULL;
PEPROCESS pFirstEprocess = NULL;
ULONG ulProcessName = 0;
ULONG ulProcessId = 0;
pEprocess = PsGetCurrentProcess(); //get system process _eprocess_address
if (pEprocess == 0)
KdPrint(("PsGetcurrentProcess Error! \\r\\n"));
return STATUS_SUCCESS;
KdPrint(("pEprocess addr is:%08x\\r\\n",pEprocess));
pFirstEprocess = pEprocess;
while (pEprocess )
ulProcessName = (ULONG)pEprocess+0x174;
ulProcessId = *(ULONG *) ((ULONG)pEprocess+0x84);
KdPrint(("PID=%d,process_name=%s",ulProcessId,ulProcessName));
pEprocess = (PEPROCESS)(*(ULONG*)((ULONG)pEprocess+0x88)-0x88); //pointer to the list ,not the eprocess_start,SO -0x88
//双向链表,到最末尾向指向头结点,表示结束。要么就是PID不大于0,这个不知道从哪里得来的
if (pEprocess == pFirstEprocess || ( *(LONG*)( (LONG)pEprocess+0x84 ) <= 0 ))
KdPrint(("enum over !\\r\\n"));
break;
return STATUS_SUCCESS;
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING registeryPath)
KdPrint(("Driver loaded"));
KdPrint(("just a test."));
pDriverObject->DriverUnload = OnUnload;
enum_services();
return STATUS_SUCCESS;
注意:
pEprocess = (PEPROCESS)(*(ULONG*)((ULONG)pEprocess+0x88)-0x88);
//pointer to the list ,not the eprocess_start,SO -0x88
不能看到两个0x88相减,就以为是0.因为一个前0x88要当指针取值,取完之后才减去0x88.(即取地址,得到结果,结果-0x88)。
和PEB中的—ldr_data_table_entry 一样,链表指向的是下一个相同链表结构的地址,而不是下一个进程eprocess节点的头地址。所以需要-0x88。
DEBUG_VIEW输出:
00000001 0.00000000 OnUnload called
00000002 2.50107551 Driver loaded
00000003 2.50109267 just a test.
00000004 2.50110865 pEprocess addr is:865b7660
00000005 2.50112438 PID=4,process_name=System
00000006 2.50113988 PID=548,process_name=smss.exe
......
......
00000034 2.50157094 PID=1812,process_name=cmd.exe
00000035 2.50158644 PID=1588,process_name=notepad.exe
00000036 2.50160122 enum over !
demo是一个DDK驱动,DDK应该是最多到winxp能用;
PsGetCurrentProcess
一个关于PsGetCurrentProcess函数的描述如下,
通过PsGetCurrentProcess函数获取函数名
通过PsGetCurrentProcess函数来获取当前调用驱动的进程的EPROCESS结构的地址.EPROCESS结构的0x174偏移处存放着进程名.
思路如下:
驱动程序的加载函数DriverEntry是运行在System进程中的.
(1) 通过PsGetCurrentProcess可以获取System进程的内核EPROCESS结构的地址,
(2) 从该地址开始寻找"System"字符串.
(3) 找到了便是EPROCESS的进程名存放的偏移处,得到进程名在EPROCESS结构的偏移后,
(4) 进程调用驱动的时候,就可以直接在该偏移处获取当前进程名.
代码如下:
DWORD GetProcessNameOffset()
PEPROCESS curproc;
DWORD procNameOffset;
//获取EPROCESS结构的地址
curproc = PsGetCurrentProcess();
for(int i=0; i< 4096; i++)
if( !strncmp( "System", (PCHAR) curproc + i, strlen("System") ))
procNameOffset = i;
return procNameOffset;
return 0;
见此,https://www.cnblogs.com/xiaojinma/archive/2012/12/07/2806543.html
以上是关于内核级进程遍历的主要内容,如果未能解决你的问题,请参考以下文章