遍历进程有多种方法,我是用的是 CreateToolhelp32Snapshot 进程快照的方式;遍历模块我用的是 Process Status Helper 的函数,VC6需要下载 psapi.h 和相应的静态库文件,我已经上传好了。
https://pan.baidu.com/s/1AY-6J1rZ0nM4QGIy4uSVkQ
提取码:ord2
我下面的代码可以用32位的VC6或者visual studio编译,可以遍历32/64位进程,但是只能遍历32位进程的模块,因为32位编译的 EnumProcessModules 函数只能枚举32位进程的模块。如果程序是64位的,则可以枚举64位进程的模块,如果需要使程序能枚举64位进程模块,可以自行修改(要改的地方应该蛮多的,涉及指针强转的都要改)。
程序运行结果是这样的:
打印了程序和子模块的 ImageBase 和 SizeOfImage

代码
// EnumProcessAndModules.cpp : Defines the entry point for the console application.
//
#include "StdAfx.h"
#include <stdio.h>
#include <MALLOC.H>
#include <windows.h>
#include <LOCALE.h>
#include <TLHELP32.H>
#include <psapi.h>
#pragma comment(lib,"psapi.lib")
#include <vector>
#ifdef _UNICODE
#define _tprintf wprintf
#else
#define _tprintf printf
#endif
struct ModuleInfo
{
TCHAR szExeFile[MAX_PATH]; // 模块文件名
DWORD ImageBase;
DWORD SizeOfImage;
};
struct ProcessInfo
{
ModuleInfo MainModuleInfo; // 主模块信息
DWORD dwPID; // 进程ID
ModuleInfo *modules; // 子模块数组
DWORD dwModules; // 子模块数量
// ~ProcessInfo()
// {
// free(modules);
// }
};
DWORD TakeProcessSnapshot(std::vector<ProcessInfo> &processInfos);
DWORD EnumModulesHandle(HANDLE hProcess, HMODULE **lpModule);
int main(int argc, char* argv[])
{
setlocale(LC_ALL, "");
std::vector<ProcessInfo> processInfos;
TakeProcessSnapshot(processInfos);
for (int i = 0; i < processInfos.size(); i++)
{
_tprintf(TEXT("PID: %6d\t%s\n"), processInfos[i].dwPID, processInfos[i].MainModuleInfo.szExeFile);
for (int j = 0; j < processInfos[i].dwModules; j++)
{
_tprintf(TEXT("\t\t%x\t%x\t%s\n"), processInfos[i].modules[j].ImageBase, processInfos[i].modules[j].SizeOfImage, processInfos[i].modules[j].szExeFile);
}
}
printf("Bye\n");
getchar();
return 0;
}
// 枚举进程地址空间内的模块句柄,返回数组长度
DWORD EnumModulesHandle(HANDLE hProcess, HMODULE **lpModule)
{
DWORD cbBytesNeeded = 0;
// 备注:EnumProcessModules 函数无法枚举64位进程的模块,除非程序以64位编译
EnumProcessModules(hProcess, NULL, 0, &cbBytesNeeded); // 计算数组大小
*lpModule = (HMODULE *)malloc(cbBytesNeeded + 0x1000);
EnumProcessModules(hProcess, *lpModule, cbBytesNeeded + 0x1000, &cbBytesNeeded); // 枚举模块句柄
return cbBytesNeeded / sizeof(HMODULE);
}
// 获取当前所有进程的信息
DWORD TakeProcessSnapshot(std::vector<ProcessInfo> &processInfos)
{
processInfos.clear();
// 获取进程快照,得到当前所有进程的PID
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, TEXT("获取进程快照失败"), TEXT("Error"), MB_OK);
return -1;
}
// 遍历进程
BOOL bNext = Process32First(hProcessSnapshot, &pe32);
while (bNext)
{
ProcessInfo psi;
memset(&psi, 0, sizeof(ProcessInfo));
lstrcpy(psi.MainModuleInfo.szExeFile, pe32.szExeFile);
psi.dwPID = pe32.th32ProcessID;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, psi.dwPID);
if (hProcess != NULL)
{
HMODULE *lpModuleHandle = NULL;
psi.dwModules = EnumModulesHandle(hProcess, &lpModuleHandle);
psi.modules = (ModuleInfo*)malloc(psi.dwModules * sizeof(ModuleInfo));
MODULEINFO moduleInfo;
for (size_t i = 0; i < psi.dwModules; i++)
{
GetModuleInformation(hProcess, lpModuleHandle[i], &moduleInfo, sizeof(MODULEINFO));
//printf("\t%x\t%x\n", lpModuleHandle[i], moduleInfo.SizeOfImage);
GetModuleFileNameEx(hProcess, lpModuleHandle[i], (psi.modules)[i].szExeFile, MAX_PATH);
(psi.modules)[i].ImageBase = (DWORD)(lpModuleHandle[i]);
(psi.modules)[i].SizeOfImage = moduleInfo.SizeOfImage;
}
free(lpModuleHandle);
}
processInfos.push_back(psi);
bNext = Process32Next(hProcessSnapshot, &pe32);
}
return 0;
}
这篇博客介绍了如何通过CreateToolhelp32Snapshot获取进程快照以及使用Process Status Helper(psapi)库的EnumProcessModules函数遍历进程模块。作者提供了适用于32位VC6或Visual Studio的代码,能够遍历32/64位进程,但仅能枚举32位进程模块。为枚举64位模块,需要对代码进行修改,主要涉及指针转换的部分。
1533

被折叠的 条评论
为什么被折叠?



