分享
 
 
 

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

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

作者:eyas

以下所说的都不是新技术,也不是新方法,偶只是收集,总结。好久以前写的,一直没好意思贴出来。让各位见笑了。

-------------------------------------------------------------------------------------------------------

首先说明本文并没有什么新的技术,只是做一些归纳总结吧。在这过程中参考了部分书籍和网上的一些资料,加上自己的一些理解,列举枚举本地/远程NT系统进程的的几种方法,希望对大家有些帮助。

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 <windows.h>

#include <stdio.h>

#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;

}

基于PSAPI,shotgun写了个比较完整的命令行下内存进程/模块查看器,可以显示内存中所有的进程及进程调用的所有模块文件(DLL),可以用来协助程序、DLL的调试,也可以用来查找DLL木马和后门。有兴趣的读者可以从http://www.patching.net/shotgun/ps.zip下载,压缩包包含C++源代码。

<<第二部分:调用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 <windows.h>

#include <tlhelp32.h>

#include <stdio.h>

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,使用方法如下,以下代码是从pwdump2中修改了一点点而来的:

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

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

typedef unsigned long NTSTATUS;

typedef unsigned short USHORT;

typedef unsigned longULONG;

typedef unsigned longDWORD;

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<ey4s@21cn.com>

Http://www.ey4s.org

Date:2001/6/23

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

#include <stdio.h>

#include <windows.h>

#include <Winnetwk.h>

#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 <ip> <UserName> <Pass>",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<ey4s@21cn.com>"

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

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

}

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

程序在Windows2000、VC++6.0环境下编译,运行良好。注意哦,远程机器要允许IPC连接和远程操作注册表才可以哦,并且需要Admin权限,编译好的程序在我的主页http://www.ey4s.org有下载。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有