程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> VC++ >> 枚舉本地-遠程NT系統進程

枚舉本地-遠程NT系統進程

編輯:VC++

作者: eyas
版權所有:http://www.ey4s.org
中文版本出處:http://www.gamehigh.net/
轉載請與作者聯系

  Windows2000中有個工具taskmgr.exe就可以比較詳細的查看當前系統進程信息,但是那是Windows GUI程序,有時候是不是覺得命令行下的東西更方便呢?其實已經有不少命令行下的枚舉系統進程的工具了,M$的Resource Kit中好象也有,但去了解他們是怎麼實現的,自己動手做出來,是不是更有意思呢:)

  進程通常被定義為一個正在運行的程序的實例,它由兩部分組成:

  <1>操作系統用來管理進程的內核對象。內核對象也是系統用來存放關於進程的統計信息的地方。

  <2>地址空間。它包含所有可執行模塊或DLL模塊的代碼和數據。它還包含動態內存分配的空間,如線程的堆棧和堆分配空間。

  枚舉系統進程的實現方法大概有四種,其中有一種可以用來枚舉遠程NT系統的進程,前提是有遠程系統的管理員權限。



<<第一部分:調用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:[email protected]

Modify:ey4s<[email protected]>

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 *);



int main(int argc,char **argv)

{

int i,iRet;

pi TaskList[MaxProcessNum];

banner();

if(argc==1)

{

iRet=GetProcessInfo(TaskList,NULL,NULL,NULL);

  printf("\nProcess Info for [LOCAL]:");

}

else if(argc==4)

{

iRet=GetProcessInfo(TaskList,argv[1],argv[2],argv[3]);

printf("\nProcess Info for [%s]:",argv[1]);

}

else

{

printf("\nUsage:%s ",argv[0]);

return 1;

}

if(iRet>0)   

for(i=0,printf("\nProcessName     ProcessID");

i<IRET;>
printf("\n%-20s %d",TaskList[i].ProcessName,TaskList[i].dwProcessID),i++); 

  return 0;

}



DWORD GetProcessInfo(pi *ProList,char *ip,char *user,char *pass)

{

  DWORD rc,dwType,dwSize,i,dwProcessIdTitle,dwProcessIdCounter,dwRet=-1;

  HKEY             hKeyNames;

  LPSTR            buf = NULL,p,p2;

  CHAR             szSubKey[1024],szProcessName[MAX_PATH];

  PPERF_DATA_BLOCK       pPerf;

  PPERF_OBJECT_TYPE      pObj;

  PPERF_INSTANCE_DEFINITION  pInst;

  PPERF_COUNTER_BLOCK     pCounter;

  PPERF_COUNTER_DEFINITION   pCounterDef;

  HKEY      ghPerfKey =NULL, // get perf data from this key

ghMachineKey = NULL; // get title index from this key

  BOOL bRemote=FALSE;



  // Look for the list of counters. Always use the neutral

  // English version, regardless of the local language. We

  // are looking for some particular keys, and we are always

  // going to do our looking in English. We are not going

  // to show the user the counter names, so there is no need

  // to go find the corresponding name in the local language.



    __try

    {

       if((ip)&&(user)&&(pass))

       {

           if(ConnIPC(ip,user,pass)!=0)

           {

              printf("\nConnect to %s failed.",ip);

              __leave;

           }

           else

              bRemote=TRUE;

      }

       //連接本地or遠程注冊表

       if(RegConnectRegistry(ip,HKEY_PERFORMANCE_DATA,

           &ghPerfKey)!=ERROR_SUCCESS)

       {

           printf("\nRegConnectRegistry() 1 failed:%d",GetLastError());

           __leave;

       }

`   if(RegConnectRegistry(ip,HKEY_LOCAL_MACHINE,&ghMachineKey)!=ERROR_SUCCESS)

       {

           printf("\nRegConnectRegistry() 2 failed:%d",GetLastError());

           __leave;

       }



sprintf( szSubKey, "%s\\%03x", REGKEY_PERF,MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL));



if(RegOpenKeyEx(ghMachineKey,szSubKey,0,KEY_READ,&hKeyNames)!=ERROR_SUCCESS)

           __leave;



       // 從counter names取得需要的緩沖區大小

if(RegQueryValueEx(hKeyNames,REGSUBKEY_COUNTERS,NULL,&dwType,NULL,&dwSize)!= ERROR_SUCCESS)

  __leave;

       //分配內存

       buf = (LPSTR) malloc( dwSize );

       if (buf == NULL)

           __leave;

       memset( buf, 0, dwSize );

       // read the counter names from the registry

if(RegQueryValueEx(ghPerfKey,REGSUBKEY_COUNTERS,NULL,&dwType,(LPBYTE) buf,&dwSize)!= ERROR_SUCCESS)

           __leave;

       // now loop thru the counter names looking for the following counters:

       //   1. "Process"     process name

       //   2. "ID Process"    process id



       // the buffer contains multiple null terminated strings and then

       // finally null terminated at the end. the strings are in pairs of

       // counter number and counter name.



       p = buf;

       while (*p)

       {

           if (p>buf)

             for( p2=p-2; isdigit(*p2); p2--) ;

           if (stricmp(p, PROCESS_COUNTER) == 0)

           {

              // look backwards for the counter number

             for( p2=p-2; isdigit(*p2); p2--) ;

              strcpy( szSubKey, p2+1 );

           }

           else if (stricmp(p, PROCESSID_COUNTER) == 0)

           {

              // look backwards for the counter number

             for( p2=p-2; isdigit(*p2); p2--) ;

              dwProcessIdTitle = atol( p2+1 );

           }

           // next string

           p += (strlen(p) + 1);

       }

       // free the counter names buffer

       free( buf );

       // allocate the initial buffer for the performance data

       dwSize = INITIAL_SIZE;

       buf = (LPSTR) malloc( dwSize );



       while (TRUE)

       {

           if (buf == NULL)

              __leave;

           memset( buf, 0, dwSize );

           rc=RegQueryValueEx(ghPerfKey,szSubKey,NULL,&dwType,(LPBYTE) buf,&dwSize);

           pPerf = (PPERF_DATA_BLOCK) buf;

           // check for success and valid perf data block signature

           if ((rc == ERROR_SUCCESS) &&

                 (dwSize > 0) &&

                 (pPerf)->Signature[0] == (WCHAR)'P' &&

                 (pPerf)->Signature[1] == (WCHAR)'E' &&

                 (pPerf)->Signature[2] == (WCHAR)'R' &&

                 (pPerf)->Signature[3] == (WCHAR)'F' )

              break;

           // if buffer is not big enough, reallocate and try again

           if (rc == ERROR_MORE_DATA)

           {

              dwSize += EXTEND_SIZE;

              buf = (LPSTR) realloc( buf, dwSize );

           }

           else __leave;

       }

       // set the perf_object_type pointer

       pObj = (PPERF_OBJECT_TYPE) ((DWORD)pPerf + pPerf->HeaderLength);

       //loop thru the performance counter definition records looking

       //for the process id counter and then save its offset



   pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD)pObj + pObj->HeaderLength);



    for (i=0; i<(DWORD)pObj->NumCounters; i++)

       {

           if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle)

           {

              dwProcessIdCounter = pCounterDef->CounterOffset;

              break;

           }

           pCounterDef++;

       }



    pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pObj + pObj->DefinitionLength);



       // loop thru the performance instance data extracting each process name

       // and process id



       for (i=0; i < (DWORD)pObj->NumInstances-1 && i<MAXPROCESSNUM; i++)>
       {

           // pointer to the process name

           p = (LPSTR) ((DWORD)pInst + pInst->NameOffset);

           // convert it to ascii

           rc = WideCharToMultiByte( CP_ACP,0,(LPCWSTR)p,-1,szProcessName,sizeof(szProcessName),NULL,NULL);



           // if we cant convert the string then use a default value

           if (!rc) strcpy( ProList[i].ProcessName, UNKNOWN_TASK );

           else strncpy(ProList[i].ProcessName, szProcessName,sizeof(ProList[i].ProcessName)-1);



           // get the process id

       pCounter = (PPERF_COUNTER_BLOCK) ((DWORD)pInst + pInst->ByteLength);

  ProList[i].dwProcessID = *((LPDWORD) ((DWORD)pCounter + dwProcessIdCounter));



           // next process

  pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pCounter + pCounter->ByteLength);

       }

       dwRet=i;

    }//end of try

    __finally

    {

       if (buf) free( buf );

       RegCloseKey( hKeyNames );

       RegCloseKey( HKEY_PERFORMANCE_DATA );

       if(bRemote)

       {

           char tmp[52],tmp2[96];

           strncpy(tmp,ip,sizeof(tmp)-1);

           wsprintf(tmp2,"\\\\%s\\ipc$",tmp);

           WNetCancelConnection2(tmp2,CONNECT_UPDATE_PROFILE,TRUE);

       }

    }

    return dwRet;

}



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



int ConnIPC(char *RemoteName,char *User,char *Pass)

{

    NETRESOURCE nr;

    char RN[50]="\\\\";



    strncat(RN,RemoteName,sizeof(RN)-11);

    strcat(RN,"\\ipc$");



    nr.dwType=RESOURCETYPE_ANY;

    nr.lpLocalName=NULL;

    nr.lpRemoteName=RN;

    nr.lpProvider=NULL;



    if(WNetAddConnection2(&nr,Pass,User,FALSE)==NO_ERROR)

       return 0;

    else

       return 1;

}



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

void banner()

{

    printf("\nPsList ==>Local and Remote process list"

           "\nPower by ey4s<[email protected]>"

           "\nhttp://www.ey4s.org"

           "\n2001/6/22\n");

}



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



   程序在Windows2000、VC++6.0環境下編譯,運行良好。注意哦,遠程機器要允許IPC連接和遠程操作注冊表才可以哦,並且需要Admin權限.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved