2014年5月10日星期六

驱动中枚举进程/线程的方法

#include <ntifs.h>

/*
本文的目的是在驱动中列举一个进程的所有的线程。
以系统进程为例子演示。

办法想采用通用稳定的,所以选择了NtQuerySystemInformation的SystemProcessInformation。
尽管http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx上如是说:
[NtQuerySystemInformation may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic.]
可是他也没有说这个功能的替换办法(尽管有几个能获取这个结构中的某几个值)。

其实这个功能是枚举进程的,不是枚举线程的。
有的地方用#define SystemProcessAndThreadInformation 5.

made by correy
made at 2014.05.10
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h
更多的信息,可看:
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/SYSTEM_INFORMATION_CLASS.html#SystemProcessInformation
http://doxygen.reactos.org/d2/d5c/ntddk__ex_8h_source.html
*/
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation = 0,
    SystemPerformanceInformation = 2,
    SystemTimeOfDayInformation = 3,
    SystemProcessInformation = 5,
    SystemProcessorPerformanceInformation = 8,
    SystemInterruptInformation = 23,
    SystemExceptionInformation = 33,
    SystemRegistryQuotaInformation = 37,
    SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;

//摘自:c:\Program Files (x86)\Windows Kits\8.0\Include\shared\minwindef.h
typedef unsigned char       BYTE;

/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h 或者
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx
注意这个是NtQuerySystemInformation用的。
*/
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//    ULONG NextEntryOffset;
//    BYTE Reserved1[52];
//    PVOID Reserved2[3];
//    HANDLE UniqueProcessId;
//    PVOID Reserved3;
//    ULONG HandleCount;
//    BYTE Reserved4[4];
//    PVOID Reserved5[11];
//    SIZE_T PeakPagefileUsage;
//    SIZE_T PrivatePageCount;
//    LARGE_INTEGER Reserved6[6];
//} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

/*
这个是ZwQuerySystemInformation用的结构。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms725506(v=vs.85).aspx
*/
typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    PVOID Reserved2[3];
    HANDLE UniqueProcessId;
    PVOID Reserved3;
    ULONG HandleCount;
    BYTE Reserved4[4];
    PVOID Reserved5[11];
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION;

/*
摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
有修改。
*/
NTSTATUS /* WINAPI NtQuerySystemInformation */ ZwQuerySystemInformation(
  _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_    PVOID SystemInformation,
  _In_       ULONG SystemInformationLength,
  _Out_opt_  PULONG ReturnLength
);


#define tag 'tset' //test


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL; 
    SYSTEM_PROCESS_INFORMATION * pspi = 0;
    SYSTEM_PROCESS_INFORMATION * pspi_temp = 0;
    ULONG SystemInformationLength = 0;
    ULONG ReturnLength = 0;
    
    KdBreakPoint();

    DriverObject->DriverUnload = Unload;    

     //获取需要的内存。
    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) && status != STATUS_INFO_LENGTH_MISMATCH)
    { 
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        return status;
    }
    ReturnLength *= 2;//第一次需求0x9700,第二次需求0x9750,所以乘以2.
    SystemInformationLength = ReturnLength;
    pspi = ExAllocatePoolWithTag( NonPagedPool, ReturnLength, tag);
    if (pspi == NULL) {
        KdPrint(("ExAllocatePoolWithTag fail with 0x%x\n",status));
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(pspi, ReturnLength);    

    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) )
    {
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        ExFreePoolWithTag( pspi, tag );
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    for (pspi_temp = pspi ; /* pspi_temp->NextEntryOffset != 0 */; /*pspi_temp++*/) //注释的都是有问题的,如少显示一个等。
    {
        KdPrint(("PID:%d\tNumberOfThreads:%d\tHandleCount:%d\n",pspi_temp->UniqueProcessId, pspi_temp->NumberOfThreads, pspi_temp->HandleCount));

        /*
        The start of the next item in the array is the address of the previous item plus the value in the NextEntryOffset member. 
        For the last item in the array, NextEntryOffset is 0.
        摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
        说明:NextEntryOffset的值是不固定的,更不是SYSTEM_PROCESS_INFORMATION结构的大小。所以不能加一个结构的大小来遍历。
        */

        if (pspi_temp->NextEntryOffset == 0)
        {
            break;
        }

        pspi_temp = (SYSTEM_PROCESS_INFORMATION *)((char *)pspi_temp + pspi_temp->NextEntryOffset);
    }

    ExFreePoolWithTag( pspi, tag );

    return status;//STATUS_SUCCESS
} 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#include <ntifs.h>
#include <windef.h>

/*
本文的目的是在驱动中列举一个进程的所有的线程。
以系统进程为例子演示。

办法想采用通用稳定的,所以选择了NtQuerySystemInformation的SystemProcessInformation。
尽管http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx上如是说:
[NtQuerySystemInformation may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic.]
可是他也没有说这个功能的替换办法(尽管有几个能获取这个结构中的某几个值)。

其实这个功能是枚举进程的,不是枚举线程的。
有的地方用#define SystemProcessAndThreadInformation 5.

其实也是可以枚举线程的,只不过有的结构还没有公开而已,或者我没有在官方的资料/WRK/wdk/msdn中找到。

made by correy
made at 2014.05.13
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
不当之处,请指正。
*/

/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h
更多的信息,可看:
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/SYSTEM_INFORMATION_CLASS.html#SystemProcessInformation
http://doxygen.reactos.org/d2/d5c/ntddk__ex_8h_source.html
*/
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation = 0,
    SystemPerformanceInformation = 2,
    SystemTimeOfDayInformation = 3,
    SystemProcessInformation = 5,
    SystemProcessorPerformanceInformation = 8,
    SystemInterruptInformation = 23,
    SystemExceptionInformation = 33,
    SystemRegistryQuotaInformation = 37,
    SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;

//摘自:c:\Program Files (x86)\Windows Kits\8.0\Include\shared\minwindef.h
//typedef unsigned char       BYTE;

/*
一下定义摘自:
C:\Program Files (x86)\Windows Kits\8.0\Include\um\winternl.h或者
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\winternl.h 或者
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx
注意这个是NtQuerySystemInformation用的。
*/
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//    ULONG NextEntryOffset;
//    BYTE Reserved1[52];
//    PVOID Reserved2[3];
//    HANDLE UniqueProcessId;
//    PVOID Reserved3;
//    ULONG HandleCount;
//    BYTE Reserved4[4];
//    PVOID Reserved5[11];
//    SIZE_T PeakPagefileUsage;
//    SIZE_T PrivatePageCount;
//    LARGE_INTEGER Reserved6[6];
//} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

/*
这个是ZwQuerySystemInformation用的结构。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms725506(v=vs.85).aspx
*/
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//    ULONG NextEntryOffset;
//    ULONG NumberOfThreads;
//    BYTE Reserved1[48];
//    PVOID Reserved2[3];
//    HANDLE UniqueProcessId;
//    PVOID Reserved3;
//    ULONG HandleCount;
//    BYTE Reserved4[4];
//    PVOID Reserved5[11];
//    SIZE_T PeakPagefileUsage;
//    SIZE_T PrivatePageCount;
//    LARGE_INTEGER Reserved6[6];
//} SYSTEM_PROCESS_INFORMATION;

//http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/Structures/SYSTEM_PROCESS_INFORMATION.html
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//  ULONG                   NextEntryOffset;
//  ULONG                   NumberOfThreads;
//  LARGE_INTEGER           Reserved[3];
//  LARGE_INTEGER           CreateTime;
//  LARGE_INTEGER           UserTime;
//  LARGE_INTEGER           KernelTime;
//  UNICODE_STRING          ImageName;
//  KPRIORITY               BasePriority;
//  HANDLE                  ProcessId;
//  HANDLE                  InheritedFromProcessId;
//  ULONG                   HandleCount;
//  ULONG                   Reserved2[2];
//  ULONG                   PrivatePageCount;
//  VM_COUNTERS             VirtualMemoryCounters;
//  IO_COUNTERS             IoCounters;
//  SYSTEM_THREAD           Threads[0];
//} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;


//摘自:http://msdn.microsoft.com/en-us/library/gg750724.aspx 这个WRK也有的。
typedef struct {
  LARGE_INTEGER KernelTime;
  LARGE_INTEGER UserTime;
  LARGE_INTEGER CreateTime;
  ULONG WaitTime;
  PVOID StartAddress;
  CLIENT_ID ClientId;
  LONG Priority;
  LONG BasePriority;
  ULONG ContextSwitches;
  ULONG ThreadState;
  ULONG WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;


//摘自:http://doxygen.reactos.org/de/d22/ndk_2extypes_8h_source.html,有修改。
typedef struct _SYSTEM_PROCESS_INFORMATION
{
     ULONG NextEntryOffset;
     ULONG NumberOfThreads;
     LARGE_INTEGER WorkingSetPrivateSize; //VISTA
     ULONG HardFaultCount; //WIN7
     ULONG NumberOfThreadsHighWatermark; //WIN7
     ULONGLONG CycleTime; //WIN7
     LARGE_INTEGER CreateTime;
     LARGE_INTEGER UserTime;
     LARGE_INTEGER KernelTime;
     UNICODE_STRING ImageName;//这个名字好像不超过15-16个字符。
     KPRIORITY BasePriority;
     HANDLE UniqueProcessId;
     HANDLE InheritedFromUniqueProcessId;
     ULONG HandleCount;
     ULONG SessionId;
     ULONG_PTR PageDirectoryBase;
 
     //
     // This part corresponds to VM_COUNTERS_EX.
     // NOTE: *NOT* THE SAME AS VM_COUNTERS!
     //
     SIZE_T PeakVirtualSize;
     SIZE_T VirtualSize;
     ULONG PageFaultCount;
     SIZE_T PeakWorkingSetSize;
     SIZE_T WorkingSetSize;
     SIZE_T QuotaPeakPagedPoolUsage;
     SIZE_T QuotaPagedPoolUsage;
     SIZE_T QuotaPeakNonPagedPoolUsage;
     SIZE_T QuotaNonPagedPoolUsage;
     SIZE_T PagefileUsage;
     SIZE_T PeakPagefileUsage;
     SIZE_T PrivatePageCount;
 
     //
     // This part corresponds to IO_COUNTERS
     //
     LARGE_INTEGER ReadOperationCount;
     LARGE_INTEGER WriteOperationCount;
     LARGE_INTEGER OtherOperationCount;
     LARGE_INTEGER ReadTransferCount;
     LARGE_INTEGER WriteTransferCount;
     LARGE_INTEGER OtherTransferCount;
     SYSTEM_THREAD_INFORMATION TH[1];//这个本来是注释掉的。
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;


//摘自:WRK。可见里面没有SYSTEM_THREAD_INFORMATION。
//typedef struct _SYSTEM_PROCESS_INFORMATION {
//    ULONG NextEntryOffset;
//    ULONG NumberOfThreads;
//    LARGE_INTEGER SpareLi1;
//    LARGE_INTEGER SpareLi2;
//    LARGE_INTEGER SpareLi3;
//    LARGE_INTEGER CreateTime;
//    LARGE_INTEGER UserTime;
//    LARGE_INTEGER KernelTime;
//    UNICODE_STRING ImageName;
//    KPRIORITY BasePriority;
//    HANDLE UniqueProcessId;
//    HANDLE InheritedFromUniqueProcessId;
//    ULONG HandleCount;
//    ULONG SessionId;
//    ULONG_PTR PageDirectoryBase;
//    SIZE_T PeakVirtualSize;
//    SIZE_T VirtualSize;
//    ULONG PageFaultCount;
//    SIZE_T PeakWorkingSetSize;
//    SIZE_T WorkingSetSize;
//    SIZE_T QuotaPeakPagedPoolUsage;
//    SIZE_T QuotaPagedPoolUsage;
//    SIZE_T QuotaPeakNonPagedPoolUsage;
//    SIZE_T QuotaNonPagedPoolUsage;
//    SIZE_T PagefileUsage;
//    SIZE_T PeakPagefileUsage;
//    SIZE_T PrivatePageCount;
//    LARGE_INTEGER ReadOperationCount;
//    LARGE_INTEGER WriteOperationCount;
//    LARGE_INTEGER OtherOperationCount;
//    LARGE_INTEGER ReadTransferCount;
//    LARGE_INTEGER WriteTransferCount;
//    LARGE_INTEGER OtherTransferCount;
//} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;


//http://msdn.microsoft.com/en-us/library/cc248685.aspx
typedef struct _NT6_TS_UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  //[size_is(MaximumLength/2), length_is(Length/2)] 
  PWSTR Buffer;
} NT6_TS_UNICODE_STRING;


/*
http://msdn.microsoft.com/en-us/library/cc248684.aspx
http://msdn.microsoft.com/en-us/library/cc248873.aspx 这是allproc.h,但是WDK和WRK里面都没有,注释wdk8.1我没有安装。
*/
typedef struct _TS_SYS_PROCESS_INFORMATION_NT6 {
  ULONG NextEntryOffset;
  ULONG NumberOfThreads;
  LARGE_INTEGER SpareLi1;
  LARGE_INTEGER SpareLi2;
  LARGE_INTEGER SpareLi3;
  LARGE_INTEGER CreateTime;
  LARGE_INTEGER UserTime;
  LARGE_INTEGER KernelTime;
  NT6_TS_UNICODE_STRING ImageName;
  LONG BasePriority;
  DWORD UniqueProcessId;
  DWORD InheritedFromUniqueProcessId;
  ULONG HandleCount;
  ULONG SessionId;
  ULONG SpareUl3;
  SIZE_T PeakVirtualSize;
  SIZE_T VirtualSize;
  ULONG PageFaultCount;
  ULONG PeakWorkingSetSize;
  ULONG WorkingSetSize;
  SIZE_T QuotaPeakPagedPoolUsage;
  SIZE_T QuotaPagedPoolUsage;
  SIZE_T QuotaPeakNonPagedPoolUsage;
  SIZE_T QuotaNonPagedPoolUsage;
  SIZE_T PagefileUsage;
  SIZE_T PeakPagefileUsage;
  SIZE_T PrivatePageCount;

  //这个结构和SYSTEM_PROCESS_INFORMATION差不多,不过后面少了些。
} TS_SYS_PROCESS_INFORMATION_NT6, *PTS_SYS_PROCESS_INFORMATION_NT6;


/*
摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
有修改。
*/
NTSTATUS /* WINAPI NtQuerySystemInformation */ ZwQuerySystemInformation(
  _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_    PVOID SystemInformation,
  _In_       ULONG SystemInformationLength,
  _Out_opt_  PULONG ReturnLength
);


#define tag 'tset' //test


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL; 
    SYSTEM_PROCESS_INFORMATION * pspi = 0;
    SYSTEM_PROCESS_INFORMATION * pspi_temp = 0;
    ULONG SystemInformationLength = 0;
    ULONG ReturnLength = 0;
    ULONG i = 0;
    PSYSTEM_THREAD_INFORMATION psti = 0;
    
    KdBreakPoint();

    DriverObject->DriverUnload = Unload;    

     //获取需要的内存。
    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) && status != STATUS_INFO_LENGTH_MISMATCH)
    { 
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        return status;
    }
    ReturnLength *= 2;//第一次需求0x9700,第二次需求0x9750,所以乘以2.
    SystemInformationLength = ReturnLength;
    pspi = ExAllocatePoolWithTag( NonPagedPool, ReturnLength, tag);
    if (pspi == NULL) {
        KdPrint(("ExAllocatePoolWithTag fail with 0x%x\n",status));
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(pspi, ReturnLength);    

    status = ZwQuerySystemInformation(SystemProcessInformation, pspi, SystemInformationLength, &ReturnLength);
    if( !NT_SUCCESS( status ) )
    {
        KdPrint(("ZwQuerySystemInformation fail with 0x%x in line %d\n",status, __LINE__));
        ExFreePoolWithTag( pspi, tag );
        return status;
    }

    //枚举进程信息。
    //判定系统进程的好的办法是和PEPROCESS PsInitialSystemProcess比较。
    for (pspi_temp = pspi ; /* pspi_temp->NextEntryOffset != 0 */; /*pspi_temp++*/) //注释的都是有问题的,如少显示一个等,可以改为while。
    {
        KdPrint(("PID:%d\tNumberOfThreads:%d\tHandleCount:%d\n",pspi_temp->UniqueProcessId, pspi_temp->NumberOfThreads, pspi_temp->HandleCount));

        //枚举线程信息。
        for (i = 0, psti = pspi_temp->TH; i < pspi_temp->NumberOfThreads; i++)
        {
            /*
            注意:
            1.有同一个地址跑多个线程的情况。特别是在系统进程。
            2.X64系统上有的线程地址为0等.感觉这个不重要,重要的是获取了TID。
            */            
            KdPrint(("    TID:%d属于PID:%d,StartAddress:%p\n", psti->ClientId.UniqueThread, psti->ClientId.UniqueProcess, psti->StartAddress));

            /*
            并且断言:psti <= ((char *)pspi_temp + pspi_temp->NextEntryOffset)
            */
            psti = (PSYSTEM_THREAD_INFORMATION)((char *)psti + sizeof(SYSTEM_THREAD_INFORMATION));
        }

        /*
        The start of the next item in the array is the address of the previous item plus the value in the NextEntryOffset member. 
        For the last item in the array, NextEntryOffset is 0.
        摘自:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx。
        说明:NextEntryOffset的值是不固定的,更不是SYSTEM_PROCESS_INFORMATION结构的大小。所以不能加一个结构的大小来遍历。
        */

        if (pspi_temp->NextEntryOffset == 0)
        {
            break;
        }

        pspi_temp = (SYSTEM_PROCESS_INFORMATION *)((char *)pspi_temp + pspi_temp->NextEntryOffset);
    }

    ExFreePoolWithTag( pspi, tag );

    return status;//STATUS_SUCCESS
} 

没有评论:

发表评论