内核级进程遍历

原理

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   //进程名
   ...
   +0x1b0 Peb              : Ptr32 _PEB   //PEB,本节用不到
      +0x000 InheritedAddressSpace : UChar
      +0x001 ReadImageFileExecOptions : UChar
      +0x002 BeingDebugged    : UChar
      +0x003 SpareBool        : UChar
      +0x004 Mutant           : Ptr32 Void
      +0x008 ImageBaseAddress : Ptr32 Void
      +0x00c Ldr              : Ptr32 _PEB_LDR_DATA  //指向模块结点表头
      ...
   ...
   +0x258 Cookie           : Uint4B

demo
用的vs2008sp1 on xp sp3,visual ddk。
其中工程选项中没有使用了visual studio,而部没有用ddk compiler,即使这样,用默认的结构去生成解决方案,还是无法加载。于是我全删掉,自己写,好在有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;
    //lkd> !process 0 0
    //lkd> dt _eprocess xxxxxxxx
    //+0x174 ImageFileName    : [16]  "smss.exe"
    //+0x084 UniqueProcessId  : 0x00000224 Void
    //lkd> db 864bb0a8-0x88+0x174
    //864bb194  73 6d 73 73 2e 65 78 65-00 00 00 00 00 00 00 00  smss.exe........ ascii 

    while (pEprocess )
    {
        ulProcessName = (ULONG)pEprocess+0x174;
        ulProcessId   =  *(ULONG *) ((ULONG)pEprocess+0x84);
        KdPrint(("PID=%d,process_name=%s",ulProcessId,ulProcessName));

//      +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x862669a8 - 0x865b76e8 ]
//      +0x000 Flink            : 0x862669a8 _LIST_ENTRY [ 0x863570a8 - 0x864bb0a8 ]
//      +0x004 Blink            : 0x865b76e8 _LIST_ENTRY [ 0x864bb0a8 - 0x8055b158 ]
        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
  1. 不能看到两个0x88相减,就以为是0.因为一个前0x88要当指针取值,取完之后才减去0x88.(即取地址,得到结果,结果-0x88)。
  2. 和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   
00000007    2.50115538  PID=612,process_name=csrss.exe  
00000008    2.50117064  PID=636,process_name=winlogon.exe   
00000009    2.50118613  PID=688,process_name=services.exe   
00000010    2.50120139  PID=700,process_name=lsass.exe  
00000011    2.50121689  PID=856,process_name=vmacthlp.exe   
00000012    2.50123215  PID=868,process_name=svchost.exe    
00000013    2.50124717  PID=952,process_name=svchost.exe    
00000014    2.50126266  PID=1044,process_name=svchost.exe   
00000015    2.50127792  PID=1100,process_name=svchost.exe   
00000016    2.50129294  PID=1160,process_name=svchost.exe   
00000017    2.50130844  PID=1416,process_name=spoolsv.exe   
00000018    2.50132370  PID=1664,process_name=vmtoolsd.exe  
00000019    2.50133944  PID=1956,process_name=explorer.exe  
00000020    2.50135541  PID=496,process_name=vmtoolsd.exe   
00000021    2.50137067  PID=536,process_name=ctfmon.exe 
00000022    2.50138617  PID=1256,process_name=alg.exe   
00000023    2.50140166  PID=1772,process_name=wscntfy.exe   
00000024    2.50141716  PID=448,process_name=devenv.exe 
00000025    2.50143218  PID=524,process_name=conime.exe 
00000026    2.50144792  PID=184,process_name=Kernel Detectiv    
00000027    2.50146341  PID=1284,process_name=windbg.exe    
00000028    2.50147891  PID=1700,process_name=OSRLOADER.exe 
00000029    2.50149441  PID=1880,process_name=Dbgview.exe   
00000030    2.50150990  PID=428,process_name=mspdbsrv.exe   
00000031    2.50152516  PID=1788,process_name=procexp.exe   
00000032    2.50154066  PID=1656,process_name=wmiprvse.exe  
00000033    2.50155592  PID=244,process_name=calc.exe   
00000034    2.50157094  PID=1812,process_name=cmd.exe   
00000035    2.50158644  PID=1588,process_name=notepad.exe   
00000036    2.50160122  enum over !     

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。