进程枚举是将系统中的所有进程显示出来,就像Windows中的任务管理器一样,可以看到系统中运行的所有进程。
进程枚举的四种方法:
-
通过系统快照进行枚举
-
通过psapi.dll中的函数进行枚举
-
通过WtsApi32.dll中的函数进行枚举
-
通过ntdll.dll中的函数进行枚举
第一种、通过系统快照进行枚举
1、CreateToolhelp32Snapshot()
CreateToolhelp32Snapshot可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。
HANDLE WINAPI CreateToolhelp32Snapshot(
DWORD dwFlags, //用来指定“快照”中需要返回的对象,可以是TH32CS_SNAPPROCESS等
DWORD th32ProcessID //一个进程ID号,用来指定要获取哪一个进程的快照,当获取系统进程列表或获取 当前进程快照时可以设为0
);
参数:
- dwFlags指定快照中包含的系统内容,这个参数能够使用下列数值(常量)中的一个或多个。
TH32CS_INHERIT(0x80000000) | - 声明快照句柄是可继承的。 |
TH32CS_SNAPALL | - 在快照中包含系统中所有的进程和线程。 |
TH32CS_SNAPHEAPLIST(0x00000001) | - 在快照中包含在th32ProcessID中指定的进程的所有的堆。 |
TH32CS_SNAPMODULE(0x00000008) | - 在快照中包含在th32ProcessID中指定的进程的所有的模块。 |
TH32CS_SNAPPROCESS(0x00000002) | - 在快照中包含系统中所有的进程。 |
TH32CS_SNAPTHREAD(0x00000004) | - 在快照中包含系统中所有的线程。 |
H32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE)
- th32ProcessID指定将要快照的进程ID。如果该参数为0表示快照当前进程。该参数只有在设置了TH32CS_SNAPHEAPLIST或者TH32CS_SNAPMODULE后才有效,在其他情况下该参数被忽略,所有的进程都会被快照。
- 返回值
调用成功,返回快照的句柄,调用失败,返回INVALID_HANDLE_VALUE 。
2、Process32First()
process32First是一个进程获取函数,当我们利用函数CreateToolhelp32Snapshot()获得当前运行进程的快照后,我们可以利用process32First函数来获得
BOOL WINAPI Process32First(
HANDLE hSnapshot,//_in
LPPROCESSENTRY32 lppe//_out
);
- hSnapshot是快照句柄,
- lppe是一个指向PROCESSENTRY32结构的指针,进程信息将会被返回到这个结构中。
PROCESSENTRY32 结构如下:
typedef struct tagPROCESSENTRY32 {
DWORD dwSize; // 结构大小;
DWORD cntUsage; // 此进程的引用计数;
DWORD th32ProcessID; // 进程ID;
DWORD th32DefaultHeapID; // 进程默认堆ID;
DWORD th32ModuleID; // 进程模块ID;
DWORD cntThreads; // 此进程开启的线程计数;
DWORD th32ParentProcessID;// 父进程ID;
LONG pcPriClassBase; // 线程优先权;
DWORD dwFlags; // 保留;
WCHAR szExeFile[MAX_PATH]; // 进程全名;
} PROCESSENTRY32;
3、Process32Next()
Process32Next(
Handle hsnapShot,
LPPROCESSENTRY32 lppe
)
Process32Next是获取快照中的下一个进程的函数,当我们利用函数CreateToolhelp32Snapshot()获得当前运行进程的快照后,我们可以利用process32First函数来获得
- hSnapshot是快照句柄,
- lppe是一个指向PROCESSENTRY32结构的指针,进程信息将会被返回到这个结构中。
PROCESSENTRY32 结构如下
typedef struct tagPROCESSENTRY32 {
DWORD dwSize; // 结构大小;
DWORD cntUsage; // 此进程的引用计数;
DWORD th32ProcessID; // 进程ID;
DWORD th32DefaultHeapID; // 进程默认堆ID;
DWORD th32ModuleID; // 进程模块ID;
DWORD cntThreads; // 此进程开启的线程计数;
DWORD th32ParentProcessID;// 父进程ID;
LONG pcPriClassBase; // 线程优先权;
DWORD dwFlags; // 保留;
WCHAR szExeFile[MAX_PATH]; // 进程全名;
} PROCESSENTRY32;
实例:
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
int main()
{
PROCESSENTRY32 processEntry = {0};
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return -1;
}
processEntry.dwSize = sizeof(PROCESSENTRY32);
BOOL bRet = Process32First(hProcessSnap, &processEntry);
while (bRet)
{
printf("ProcessID:%d (%s)\n", processEntry.th32ProcessID, processEntry.szExeFile);
bRet = Process32Next(hProcessSnap, &processEntry);
}
CloseHandle(hProcessSnap);
system("pause");
return 0;
}
第二种、通过psapi.dll中的函数进行枚举
1、EnumProcesses()
EnumProcesses。检索进程中的每一个进程标识符.。EnumProcesses函数主要功能得到一系列过程采用EnumProcesses功能。为每个过程、主要功能通过工艺标识符调用PrintModules功能。
BOOL WINAPI EnumProcesses(
DWORD * pProcessIds,
DWORD CB,
DWORD * pBytesReturned
);
- pProcessIds接收进程标识符的数组.
- cb数组的大小.
- pBytesReturned数组返回的字节数
- 成功返回非零数,失败返回零,可以使用函数 GetLastError获取错误信息.
2、OpenProcess()
OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄
HANDLE OpenProcess(
DWORD dwDesiredAccess, //渴望得到的访问权限(标志)
BOOL bInheritHandle, // 是否继承句柄
DWORD dwProcessId// 进程标示符
);
PROCESS_ALL_ACCESS | :获取所有权限 |
PROCESS_CREATE_PROCESS | :创建进程 |
PROCESS_CREATE_THREAD | :创建线程 |
PROCESS_DUP_HANDLE | :使用DuplicateHandle()函数复制一个新句柄 |
PROCESS_QUERY_INFORMATION | :获取进程的令牌、退出码和优先级等信息 |
PROCESS_QUERY_LIMITED_INFORMATION | :获取进程特定的某个信息 |
PROCESS_SET_INFORMATION | :设置进程的某种信息 |
PROCESS_SET_QUOTA | :使用SetProcessWorkingSetSize函数设置内存限制 |
PROCESS_SUSPEND_RESUME | :暂停或者恢复一个进程 |
PROCESS_TERMINATE | :使用Terminate函数终止进程 |
PROCESS_VM_OPERATION | :在进程的地址空间执行操作 |
PROCESS_VM_READ | :使用ReadProcessMemory函数在进程中读取内存 |
PROCESS_VM_WRITE | :使用WriteProcessMemory函数在进程中写入内存 |
SYNCHRONIZE | :使用wait函数等待进程终止 |
- bInheritHandle:TRUE或者FALSE
- dwProcessId:pid
- 返回值如成功,返回值为指定进程的句柄如失败,返回值为空,可调用GetLastError获得错误代码。
3、EnumProcessModles()
获得指定进程中所有模块的句柄。
BOOL WINAPI EnumProcessModules(
in HANDLE hProcess,
out HMODULE *lphModule,
in DWORD cb,
out LPDWORD lpcbNeeded
);
- hProcess [传入]指定进程的句柄。
- lphModule [传出]用来存放所有模块句柄的数组。
- cb [传入]lphModule参数所传入的数组的大小,单位是字节。
- lpcbNeeded [传出]要把所有模块的句柄存放进lphModule参数所传入的数组中,所需要的字节数。
- 返回
如果函数执行成功,则返回值为非零。果函数执行失败,则返回值为零。可以调用 GetLastError函数来获得更多的错误信息。
4、GetModuleFileNameEx()
获取指定模块的文件名称
DWORD GetModuleFileNameEx(
HANDLE hProcess, //进程的句柄
HMODULE hModule, // 获取模块的句柄
LPTSTR lpFilename, //接收的地址空间
DWORD nSize // 接收空间的大小
);
- hProcess, //进程的句柄
- hModule, // 获取模块的句柄
- lpFilename, //接收的地址空间
- nSize // 接收空间的大小
- 返回值:如果获取成功,则返回一个接收地址空间的大小如果不成功返回值为0,可以使用GetLastError()函数获取返回的具体信息。
例程:此例程总共分为以下几个步骤:
第一步、通过EnunProcesses()函数获取进程中系统中所有的进程,将获取到的进程标识符(进程ID)放入到一个数组中(此函数的第一个参数)中,
第二步、OpenProcess函数通过获取到的进程标识符打开进程,如果打开成功,则返回进程的句柄。
第三步、EnumProcessModles函数通过OpenProcess函数返回的进程句柄枚举进程中所有的模块,并将获取的到的所有模块句柄储存到一个数组中(此函数的第二个参数)
第四步、使用GetModuleFileNameEx函数通过进程和模块的句柄获取当前进程中所有模块的名称。并将其存储到一个地址空间中(此函数的第三个参数)
#include <Windows.h>
#include <stdio.h>
#include <Psapi.h>
#include <stdlib.h>
int main()
{
//提升进程权限
//打开令牌
HANDLE hToken;//创建令牌句柄
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS | TOKEN_QUERY, &hToken))//打开令牌句柄,设置令牌权限
{
printf("OpenProcessToken Failed.");
return -1;
}
TOKEN_PRIVILEGES tkp;
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);//查看令牌权限
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
printf("AdjustTokenPrivileges Failed.");
return -1;
}
//枚举进程
DWORD ProcessId[1024];
DWORD cbNeeded;
DWORD processcount;
if (!EnumProcesses(ProcessId,sizeof(ProcessId),&cbNeeded))//枚举所有进程的ID
{
printf("Failed.");
return -1;
}
processcount = cbNeeded / sizeof(DWORD);
printf("当前一共有%d个进程\n\n",processcount);
HMODULE hMods[1024];
for (DWORD i = 0; i < processcount; i++)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,ProcessId[i]);//通过ID,打开所有的进程
if (hProcess)
{
//printf("\nProcessID:%d 打开成功\n",ProcessId[i]);
if (EnumProcessModules(hProcess,hMods,sizeof(hMods),&cbNeeded))//通过EnumProcessModules获取进程模块
{
for (int j = 0; j < (cbNeeded/sizeof(HMODULE)); j++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess,hMods[j],szModName,sizeof(szModName)/sizeof(TCHAR)))
{
printf("\t%d %s (0x%08)\n",j,szModName,hMods[j]);
}
}
}
}
else
{
printf("\nProcessID:%d 打开失败\n", ProcessId[i]);
}
//printf("ProcessId: %d\n",ProcessId[i]);
}
system("pause");
return 0;
}
第三种、通过WtsApi32.dll中的函数进行枚举
此方式中,是将电脑当做一台终端服务器来枚举系统中的进程,使用的函数小编没有找到资料,以自己的理解对这个方式进行描述。
例程:
第一步、使用WTSOpenServer函数通过计算机名称获取终端服务器的句柄。
第二步、通过WTSEnumerateProcesses函数枚举系统的进程,并将获取的经常信息放入到一个进程结构体重(此函数的第四个参数)
第三步、关闭终端服务器的句柄
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <WtsApi32.h>
#pragma comment(lib,"WtsApi32.lib")
int main()
{
DWORD i;
char* szServerName = "DESKTOP-IIOTQRA";//定义自己的计算机名
HANDLE hWtsServer = WTSOpenServer(szServerName);//通过计算机名打开一个特殊终端服务器的句柄,并且返回句柄
PWTS_PROCESS_INFO pWtspi;//定义一个结构体,保存终端进程的信息
DWORD dwCount;
if (!WTSEnumerateProcesses(hWtsServer,0,1,&pWtspi,&dwCount))//枚举系统进程
{
printf("Error!");
return -1;
}
for ( i = 0; i < dwCount; i++)
{
printf("ProcessID : %d (%s)\n",pWtspi[i].ProcessId,pWtspi[i].pProcessName);
}
WTSCloseServer(hWtsServer);//关闭特殊终端服务器的句柄
system("pause");
return 0;
}
第四种、通过ntdll.dll中的函数进行枚举
#include <iostream>
#include <Windows.h>
#include <NTSecAPI.h>
using namespace std;
typedef DWORD(WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);//使用指针函数,调用用函数GetProcAddress
#define SystemProcessesAndThreadsInformation 5 //定义GetProcAddress函数要访问的的形式
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;
int main()
{
HMODULE hNtDLL = GetModuleHandle("ntdll.dll");//动态获取ntdll.dll,如果获取成功返回一个句柄。
if (!hNtDLL)
{
cout << "Error: -1" << endl;
return -1;
}
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDLL, "ZwQuerySystemInformation");//
//动态获取GetProcAddress,将此函数模块的首地址返回给指针函数ZwQuerySystemInformation
ULONG cbBuffer = 0x10000;
LPVOID pBuffer = NULL;
pBuffer = malloc(cbBuffer);//分配一个内存地址空间
if (pBuffer == NULL)
{
cout << "Error: -2" << endl;
return -2;
}
ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, pBuffer, cbBuffer, NULL);//通过指针函数将系统中的进程进行枚举
PSYSTEM_PROCESS_INFORMATION pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;//将分配内存地址中的内容转换成进程信息结构的结构体信息
for (;;)
{
printf("ProcessID: %d (%ls)\n", pInfo->ProcessId, pInfo->ProcessName.Buffer);
if (pInfo->NextEntryDelta == 0)
break;
pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo) + pInfo->NextEntryDelta);//指向下一个将进程信息结构元素
}
free(pBuffer);//释放分配的内存地址
system("pause");
return 0;
}
注意:此文章只作为小编的笔记,有部分资料参照网上,若有侵权,请联系删除。