首页 网络安全 安全学院 查看内容

枚举本地-远程NT系统进程

2009-6-28 11:18 800 0

摘要:   Windows2000中有个工具taskmgr.exe就可以比较详细的查看当前系统进程信息,但是那是Windows GUI程序,有时候是不是觉得命令行下的东西更方便呢?其实已经有不少命令行下的枚举...
关键词: 进程 函数 Process 系统 COUNTER PPERF NULL printf char DWORD

  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 "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   **********************************************************************/   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,使用方法如下:   ////////////////////////////////////////////////////////////////////////////////   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   Http://www.ey4s.org   Date:2001/6/23   **************************************************************************/   #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\\%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   {   // 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"   "\http://www.ey4s.org"   "\n2001/6/22\n");   }   程序在Windows2000、VC++6.0环境下编译,运行良好。注意哦,远程机器要允许IPC连接和远程操作注册表才可以哦,并且需要Admin权限.
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部