全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1257
推到 Plurk!
推到 Facebook!

枚舉本地遠端NT系統進程

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-07-24 17:29:02 IP:61.64.xxx.xxx 未訂閱
枚舉本地遠端NT系統進程
http://www.sron.net/art/article.php?articleid=227    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: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 *);        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 
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\\x", 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 
       {               // 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"               "\nhttp://www.ey4s.org"               "\n2001/6/22\n");    }        /////////////////////////////////////////////////////////////////////
///////////           程式在Windows2000、VC  6.0環境下編譯,運行良好。注意哦,遠端機器要允許IPC
連接和遠端操作註冊表才可以哦,並且需要Admin許可權.     
發表人 - conundrum 於 2004/07/24 17:37:27
系統時間:2024-05-11 16:37:19
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!