现在的位置: 首页 > 综合 > 正文

调用PSAPI函数枚举系统进程

2013年12月03日 ⁄ 综合 ⁄ 共 5541字 ⁄ 字号 评论关闭

<<第一部分:调用PSAPI函数枚举系统进程>>

   M$的Windows NT开发小组开发了自己Process Status函数,包含在PSAPI.DLL文件中,这些函数只能在高于NT4.0以后的版本中使用。PSAPI一共有14个函数[实际PSAPI.DLL输出函数有19个,但其中有5个函数有两个版本,分别是ANSI和Unicode版本],通过调用这些函数,我们可以很方便的取得系统进程的所有信息,例如进程名、进程ID、父进程ID、进程优先级、映射到进程空间的模块列表等等。为了方便起见,以下的例子程序只获取进程的名字和ID。

   简单的程序如下:

/*******************************************************

Module:ps.c

说明:调用PSAPI函数枚举系统进程名和ID,Only for NT/2000

*************************************************/

#include

#include

#include "psapi.h"

#pragma comment(lib,"psapi.lib")

void PrintProcessNameAndID( DWORD processID )

{

   char szProcessName[MAX_PATH] = "unknown";

   //取得进程的句柄

   HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |

                  PROCESS_VM_READ,

                  FALSE, processID );

   //取得进程名称

   if ( hProcess )

   {

     HMODULE hMod;

     DWORD cbNeeded;

     if ( EnumProcessModules( hProcess, &hMod,
sizeof(hMod), &cbNeeded) )

      GetModuleBaseName( hProcess, hMod, szProcessName,

sizeof(szProcessName) );

   }

   //回显进程名称和ID

   printf( "/n%-20s%-20d", szProcessName, processID );

   CloseHandle( hProcess );

}

void main( )

{

   DWORD aProcesses[1024], cbNeeded, cProcesses;

   unsigned int i;

   //枚举系统进程ID列表

   if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )

     return;

   // Calculate how many process identifiers were returned.

   //计算进程数量

   cProcesses = cbNeeded / sizeof(DWORD);

   // 输出每个进程的名称和ID

   for ( i = 0; i < cProcesses; i++ )

    PrintProcessNameAndID( aProcesses[i] );

   return;

}

<<第二部分:调用ToolHelp API枚举本地系统进程>>

  在第一部分提到的PSAPI函数只能枚举NT系统的进程,在Windows9x环境下我们可以通过调用ToolHelp API函数来达到枚举系统进程的目的。M$的Windows NT开发小组因为不喜欢ToolHelp函数,所以没有将这些函数添加给Windows NT,所以他们开发了自己的Process Status函数,就是第一部分提到的PSAPI了。但是后来M$已经将ToolHelp函数添加给了Windows 2000。ToolHelp共有12个函数,通过调用这些函数可以方面的取得本地系统进程的详细信息,以下这个简单的例子只调用了三个函数,获取我们所需要系统进程名字和进程ID。程序如下:

/**********************************************************************

Module:ps.c

说明:调用ToolHelp函数枚举本地系统进程名和ID,Only for 9x/2000

**********************************************************************/

#include

#include

#include

int main()

{

  HANDLE     hProcessSnap = NULL;

   PROCESSENTRY32 pe32   = {0};

   hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

   if (hProcessSnap == (HANDLE)-1)

   {

    printf("/nCreateToolhelp32Snapshot() failed:%d",GetLastError());

   return 1;

}

   pe32.dwSize = sizeof(PROCESSENTRY32);

  printf("/nProcessName     ProcessID");

   if (Process32First(hProcessSnap, &pe32))

   {

     do

     {

printf("/n%-20s%d",pe32.szExeFile,pe32.th32ProcessID);

     }while (Process32Next(hProcessSnap, &pe32));

   }

   else

   {

    printf("/nProcess32Firstt() failed:%d",GetLastError());

   }

   CloseHandle (hProcessSnap);

return 0;

}

<<第三部分:调用NTDLL.DLL中未公开API枚举本地系统进程>>

    第一部分和第二部分说的是调用MS公开的API来枚举系统进程,在NTDLL.DLL中其实有一个未公开API,也可以用来枚举系统进程。此方法是从别处看来的,我可没这本事自己发现哦,出处记不清楚了,好像是pwdump2 中的源代码中的一部分吧。

    OK!那个未公开API就是NtQuerySystemInformation,使用方法如下:

/////////////////////////////////////////////////////////

#include

#include

#include

typedef unsigned long NTSTATUS;

typedef unsigned short USHORT;

typedef unsigned long ULONG;

typedef unsigned long DWORD;

typedef long LONG;

typedef __int64 LONGLONG;

typedef struct {

   USHORT Length;

   USHORT MaxLen;

   USHORT *Buffer;

} UNICODE_STRING;

struct process_info {

   ULONG NextEntryDelta;

   ULONG ThreadCount;

   ULONG Reserved1[6];

   LARGE_INTEGER CreateTime;

   LARGE_INTEGER UserTime;

   LARGE_INTEGER KernelTime;

   UNICODE_STRING ProcessName;

   ULONG BasePriority;

   ULONG ProcessId;

};

typedef NTSTATUS (__stdcall *NtQuerySystemInformation1)(

     IN ULONG SysInfoClass,

IN OUT PVOID SystemInformation,

     IN ULONG SystemInformationLength,

    OUT PULONG RetLen

        );

int main()

{

   HINSTANCE hNtDll;

   NtQuerySystemInformation1 NtQuerySystemInformation;

   NTSTATUS rc;

   ULONG ulNeed = 0;

   void *buf = NULL;

   size_t len = 0;

   struct process_info *p ;

   int done;

   hNtDll = LoadLibrary ("NTDLL");

   if (!hNtDll)

     return 0;

   NtQuerySystemInformation = (NtQuerySystemInformation1)GetProcAddress (hNtDll,

"NtQuerySystemInformation");

     if (!NtQuerySystemInformation)

      return 0;

   do {

     len += 0x1000;

     buf = realloc (buf, len);

     if (!buf)

       return 0;

     rc = NtQuerySystemInformation (5, buf, len, &ulNeed);

   } while (rc == 0xc0000004); // STATUS_INFO_LEN_MISMATCH

   if (rc <0) {

     free (buf);

     return 0;

   }

  printf("/nProcessName     ProcessID");

   p = (struct process_info *)buf;

   done = 0;

   while (!done) {

     if ((p->ProcessName.Buffer != 0))

     {

      printf("/n%-20S%d",p->ProcessName.Buffer,p->ProcessId);

     }

     done = p->NextEntryDelta == 0;

     p = (struct process_info *)(((char *)p) + p->NextEntryDelta);

   }

   free (buf);

   FreeLibrary (hNtDll);

   return 0;

}

<<第四部分:从PDH中取得本地/远程系统进程信息>>

  前面说的三种方法都只能枚举本地的系统进程,如何枚举远程系统的进程呢?目前我只知道从PDH中取得进程信息。

  OK!我先简单的说说PDH是什么东西,hoho~难的偶也不会。PDH是英文Performance Data Helper的缩写,Windows NT一直在更新这个称为Performance Data的数据库,这个数据库包含了大量的信息,例如CPU使用率,内存使用率,系统进程信息等等一大堆有用的信息,可以通过注册表函数来访问。注意哦,Windows 9x中并没有配置这个数据库。但是,这个数据库中的信息布局很复杂,很多人并不愿意使用它,包括我。而且刚开始的时候,它也没有自己特定的函数,只能通过现有的注册表函数来操作。后来,为了使该数据库的使用变得容易,MS开发了一组Performance Data Helper函数,包含在PDH.DLL文件中。

Windows 2000默认是允许远程注册表操作的,所以我们就可以通过连接远程系统的注册表,从它的PDH中取得我们所需要的系统进程信息了,当然这需要远程系统的Admin权限。

OK!我们下面所举的例子是直接利用注册表函数来从本地/远程系统的PDH数据库中取得我们所需要的数据的,我们并没有利用PDH API。

    程序代码如下:

/*****************************************************

Module:ps.c

Author:mikeblas@nwlink.com

Modify:ey4s

Http://www.ey4s.org

Date:2001/6/23

*************************************************************/

#include

#include

#include

#define INITIAL_SIZE    51200

#define EXTEND_SIZE     12800

#define REGKEY_PERF     "software//microsoft//windows nt//currentversion//perflib"

#define REGSUBKEY_COUNTERS "Counters"

#define PROCESS_COUNTER   "process"

#define PROCESSID_COUNTER  "id process"

#define UNKNOWN_TASK    "unknown"

#define MaxProcessNum      52//最大进程数量

#pragma comment(lib,"mpr.lib")

typedef struct ProcessInfo

{

char ProcessName[128];

DWORD dwProcessID;

}pi;

void banner();

int ConnIPC(char *,char *,char *);

DWORD GetProcessInfo(pi *,char *,char *,char *); 

抱歉!评论已关闭.