您的位置:首页精文荟萃软件资讯 → 枚举本地远程NT系统进程

枚举本地远程NT系统进程

时间:2004/10/8 13:21:00来源:本站整理作者:蓝点我要评论(0)

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


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"

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

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

}



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



   程序在Windows2000、VC++6.0环境下编译,运行良好。注意哦,远程机器要允许IPC连接和远程操作注册表才可以哦,并且需要Admin权限.

相关阅读 Windows错误代码大全 Windows错误代码查询激活windows有什么用Mac QQ和Windows QQ聊天记录怎么合并 Mac QQ和Windows QQ聊天记录Windows 10自动更新怎么关闭 如何关闭Windows 10自动更新windows 10 rs4快速预览版17017下载错误问题Win10秋季创意者更新16291更新了什么 win10 16291更新内容windows10秋季创意者更新时间 windows10秋季创意者更新内容kb3150513补丁更新了什么 Windows 10补丁kb3150513是什么

文章评论
发表评论

热门文章 360快剪辑怎么使用 36金山词霸如何屏幕取词百度收购PPS已敲定!3

最新文章 微信3.6.0测试版更新了微信支付漏洞会造成哪 360快剪辑怎么使用 360快剪辑软件使用方法介酷骑单车是什么 酷骑单车有什么用Apple pay与支付宝有什么区别 Apple pay与贝贝特卖是正品吗 贝贝特卖网可靠吗

人气排行 xp系统停止服务怎么办?xp系统升级win7系统方电脑闹钟怎么设置 win7电脑闹钟怎么设置office2013安装教程图解:手把手教你安装与qq影音闪退怎么办 QQ影音闪退解决方法VeryCD镜像网站逐个数,电驴资料库全集同步推是什么?同步推使用方法介绍QQ2012什么时候出 最新版下载EDiary——一款好用的电子日记本