枚举进程的几种方法
来源:互联网 发布:google拼音输入法 mac 编辑:程序博客网 时间:2024/05/16 07:51
原地址:http://blog.sina.com.cn/s/blog_97312deb01017loy.html
1、利用ToolHelp API
首先创建一个系统快照,然后通过对系统快照的访问完成进程的枚举。
获取系统快照使用CreateToolhelp32Snapshot()函数
函数原型声明如下:
HANDLE WINAPICreateToolhelp32Snapshot(
DWORDdwFlags,
DWORDth32ProcessID
);
将dwFlags设置为TH32CS_SNAPPROCESS用于获取进程快照。函数调用成功后会返回一个快照的句柄,便可以使用Process32First()、Process32Next()函数进行枚举了。
函数原型声明如下:
BOOL WINAPIProcess32First(
HANDLEhSnapshot,
LPPROCESSENTRY32lppe
);
BOOL WINAPIProcess32Next(
HANDLEhSnapshot,
LPPROCESSENTRY32lppe
);
下面是相关代码:
#include<windows.h>
#include <tlhelp32.h>
#include <stdio.h>
voiduseToolHelp()
{
HANDLE procSnap =CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(procSnap == INVALID_HANDLE_VALUE)
{
printf("CreateToolhelp32Snapshot failed,%d ",GetLastError());
return;
}
//
PROCESSENTRY32 procEntry = { 0 };
procEntry.dwSize = sizeof(PROCESSENTRY32);
BOOL bRet = Process32First(procSnap,&procEntry);
while(bRet)
{
wprintf(L"PID: %d (%s)",procEntry.th32ProcessID, procEntry.szExeFile);
//在此可以做想要处理的相关工作
//...
bRet = Process32Next(procSnap,&procEntry);
}
CloseHandle(procSnap);
}
void main()
{
useToolHelp();
getchar();
}
用此方法可以在进程ID和进程名称间进行转换,即可以通过进程名称获得进程ID,也可以通过进程ID获取进程名称。
注:该方法对32位机器有效,但是对64位机器可不一定有效哟!
2、通过psapi.dll提供的函数
通过psapi.dll提供的EnumProcesses()、EnumProcessModules()函数实现
函数原型声明如下:
BOOLEnumProcesses(
DWORD*pProcessIds,
DWORD cb,
DWORD*pBytesReturned
);
BOOLEnumProcessModules(
HANDLEhProcess,
HMODULE*lphModule,
DWORDcb,
LPDWORDlpcbNeeded
);
相关代码如下:(参考MSDN)
#include<windows.h>
#include <stdio.h>
#include <tchar.h>
#include "psapi.h"
#pragma comment(lib,"psapi.lib")
void PrintProcessNameAndID(DWORD processID)
{
TCHAR szProcessName[MAX_PATH] = _T("");
HANDLE hProcess =OpenProcess(PROCESS_ALL_ACCESS , FALSE,processID);
//Process name.
if(NULL!= hProcess)
{
HMODULEhMod;
DWORDcbNeeded;
if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
{
GetModuleBaseName(hProcess,hMod, szProcessName,
sizeof(szProcessName)/ sizeof(TCHAR));
}
}
wprintf(_T("PID: %d (%s) "), processID,szProcessName);
CloseHandle(hProcess);
}
void main( )
{
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if( !EnumProcesses(aProcesses,sizeof(aProcesses), &cbNeeded) )
return;
cProcesses = cbNeeded / sizeof(DWORD);
for(i= 0; i < cProcesses; i++)
PrintProcessNameAndID(aProcesses[i]);
getchar();
}
此方法由于需要进行OpenProcess操作,所以需要一定的权限,当权限不够时,有些进程将不能被打开。
下面给出提升权限的相关代码:
voidRaisePrivilege()
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//
if( OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS,&hToken) )
{
if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid) )
{
AdjustTokenPrivileges(hToken,FALSE, &tp, NULL, NULL, 0);
}
}
if(hToken)
CloseHandle(hToken);
}
注:该方法适用于32bit,64bit机器。
3、通过ntdll.dll提供的Native API
使用Native API中ZwQuerySystemInformation()函数,指定SystemProcessesAndThreadsInformation标记获取系统调用枚举进程。由于该函数没有被导出,所以首先定义要使用到的结构和常量
// 定义调用函数指针
typedef DWORD(WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);
typedef struct _SYSTEM_PROCESS_INFORMATION
{
DWORD NextEntryDelta;
DWORD ThreadCount;
DWORD Reserved1[6];
FILETIME ftCreateTime;
FILETIME ftUserTime;
FILETIME ftKernelTime;
UNICODE_STRING ProcessName;
DWORD BasePriority;
DWORD ProcessId;
DWORD InheritedFromProcessId;
DWORD HandleCount;
DWORD Reserved2[2];
DWORD VmCounters;
DWORD dCommitCharge;
PVOID ThreadInfos[1];
}SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
#defineSystemProcessesAndThreadsInformation 5
然后动态加载ntdll.dll,获得函数的地址。便可以进行进程的枚举
相关代码如下:
#include<windows.h>
#include <ntsecapi.h>
#include <stdio.h>
typedef DWORD(WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);
typedef struct _SYSTEM_PROCESS_INFORMATION
{
DWORD NextEntryDelta;
DWORD ThreadCount;
DWORD Reserved1[6];
FILETIME ftCreateTime;
FILETIME ftUserTime;
FILETIME ftKernelTime;
UNICODE_STRING ProcessName;
DWORD BasePriority;
DWORD ProcessId;
DWORD InheritedFromProcessId;
DWORD HandleCount;
DWORD Reserved2[2];
DWORD VmCounters;
DWORD dCommitCharge;
PVOID ThreadInfos[1];
}SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
#defineSystemProcessesAndThreadsInformation 5
void main()
{
HMODULE hNtDll =GetModuleHandle(_T("ntdll.dll"));
if(!hNtDll)
return;
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation =
(ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,
"ZwQuerySystemInformation");
ULONGcbBuffer = 0x10000;
LPVOIDpBuffer = NULL;
pBuffer= malloc(cbBuffer);
if(pBuffer== NULL)
return;
ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,pBuffer,cbBuffer,NULL);
PSYSTEM_PROCESS_INFORMATIONpInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
for(;;)
{
wprintf(L"PID:%d (%ls) ",pInfo->ProcessId,pInfo->ProcessName.Buffer);
if(pInfo->NextEntryDelta== 0)
break;
pInfo= (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo) + pInfo->NextEntryDelta);
}
free(pBuffer);
getchar();
}
代码在VS2005 release + XP SP2调试通过
4、通过进程打开的句柄来枚举进程
同样使用ZwQuerySystemInformation()函数,指定SystemHandleInformation标记,取得系统调用
相关代码如下:
#include<windows.h>
#include <ntsecapi.h>
#include <ntstatus.h>
#include <stdio.h>
typedef NTSTATUS(WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);
typedef struct_SYSTEM_HANDLE_INFORMATION
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
}SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
typedef struct_SYSTEM_HANDLE_INFORMATION_EX
{
ULONG NumberOfHandles;
SYSTEM_HANDLE_INFORMATION Information[1];
}SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
#defineSystemHandleInformation 0x10 // 16
void main()
{
HMODULE hNtDll = LoadLibrary(L"ntdll.dll");
if(!hNtDll)
return;
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation =
(ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,
"ZwQuerySystemInformation");
ULONGcbBuffer = 0x4000;
LPVOIDpBuffer = NULL;
NTSTATUSsts;
do
{
pBuffer= malloc(cbBuffer);
if(pBuffer== NULL)
return;
memset(pBuffer,0,cbBuffer);
sts = ZwQuerySystemInformation(SystemHandleInformation, pBuffer,cbBuffer, NULL);
if(sts== STATUS_INFO_LENGTH_MISMATCH)
{
free(pBuffer);
pBuffer= NULL;
cbBuffer = cbBuffer * 2; // 初始分配的空间不足,加倍。
}
}while(s ==STATUS_INFO_LENGTH_MISMATCH);
PSYSTEM_HANDLE_INFORMATION_EXpInfo = (PSYSTEM_HANDLE_INFORMATION_EX)pBuffer;
ULONG OldPID = 0;
for(DWORD i = 0; i < pInfo->NumberOfHandles; i++)
{
if(OldPID!= pInfo->Information[i].ProcessId)
{
OldPID= pInfo->Information[i].ProcessId;
wprintf(L"PID:%d ",OldPID);
}
}
free(pBuffer);
pBuffer = NULL;
FreeLibrary(hNtDll);
hNtDll = NULL;
getchar();
}
另外,在进行进程“隐藏”工作的时候,此处的句柄是一件容易被忽略的地方,因此需要注意隐藏由程序打开的相关句柄,由于系统中句柄数量经常变换,所以没有什么必要修改其中的NumberOfHandles域,因为如果修改此处的值,则需要不停对句柄的变化进行维护,开销比较大。
在用户态下的进程枚举已经变得不可靠,因为一个内核级的Rootkit很容易就能够更改这些函数的返回结果,因此进程的可靠枚举应在内核态中实现,可以通过编写驱动来实现。
- 枚举进程的几种方法
- 枚举进程的几种方法
- 用户态枚举进程的几种方法
- 枚举当前进程的几种方法(总结)
- 用户态枚举进程的几种方法(转载)
- 枚举进程的方法
- java类型枚举的几种方法
- 子集枚举的几种方法
- 四种枚举当前进程的方法
- 9种枚举枚举进程的方法及实现
- C++枚举进程的方法
- 进程之间通讯的几种方法
- 进程间通信的几种方法
- 进程之间通讯的几种方法:
- 结束进程的几种方法
- 进程之间通讯的几种方法:
- 遍历进程名的几种方法
- 结束进程的几种方法
- Leecode--Set Matrix Zeroes
- coco2dx 窗口中文标题乱码的解决方法
- 第十周项目一
- Javascript对象的技巧和陷阱
- RakNet学习(17) -- Network Messages
- 枚举进程的几种方法
- Visitor模式
- springmvc
- Redis源码分析(二十)——事件ae
- strtok函数
- (Spring文档翻译)Part V, the Web 17.1 Spring Web MVC framework介绍
- 治疗神经病
- 7.粘包的解决方案
- Tomcat-----部署Web项目