【API】获取进程的所有模块名
在 Windows 操作系统中,每个运行中的进程由一组可执行文件(也称为模块)组成,该进程使用这些模块来执行其工作。这些模块包含可执行文件、库文件和驱动程序等。
在许多情况下,我们可能需要获取进程的所有模块名来分析以及进行相关操作。Windows 操作系统提供了一些 API 来获取进程的所有模块名。在本文中,我们将深入介绍这些 API 并提供一些示例以帮助您更好地理解这个过程。
1. EnumProcessModules
这是 Windows API 中一个较早的、基本的函数之一,用于列举给定进程的所有模块。参数 hProcess 标识要列举的目标进程的句柄。参数 hModuleArray 是一种输出缓冲区,用于接收枚举结果。
下面是使用 EnumProcessModules 函数获取进程的所有模块名称的示例程序:
#include <windows.h>
#include <psapi.h>
#include <iostream>
DWORD GetProcessModules(HANDLE hProcess)
{
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
_tprintf(TEXT("%s (0x%08X)
"), szModName, hMods[i]);
}
}
}
return cbNeeded / sizeof(HMODULE);
}
int main()
{
HANDLE hProcess;
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
{
return 1;
}
cProcesses = cbNeeded / sizeof(DWORD);
for (i = 0; i < cProcesses; i++)
{
if (aProcesses[i] != 0)
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
if (hProcess != NULL)
{
TCHAR szProcessName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, NULL, szProcessName, sizeof(szProcessName) / sizeof(TCHAR)))
{
_tprintf(TEXT("
Process
============
"));
_tprintf(TEXT("Process ID: %u
"), aProcesses[i]);
_tprintf(TEXT("Process Name: %s
"), szProcessName);
_tprintf(TEXT("
Modules
============
"));
GetProcessModules(hProcess);
}
CloseHandle(hProcess);
}
}
}
return 0;
}
程序通过枚举所有进程来获取每个进程的模块名称。对于每个进程,它通过枚举该进程的所有模块来获取模块的名称。如果获取成功,则在控制台窗口中打印出该模块的名称和模块的基址。
2. EnumProcessModulesEx
EnumProcessModulesEx 比 EnumProcessModules 多了一些功能。它可以按模块句柄(hModule)的大小对模块进行排序。此函数还支持过滤和筛选功能。例如,可以通过指定模块的文件名来仅列出具有特定名称的模块。
下面是使用 EnumProcessModulesEx 函数获取进程的所有模块名称的示例程序:
#include <windows.h>
#include <psapi.h>
#include <iostream>
DWORD GetProcessModulesEx(HANDLE hProcess)
{
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModulesEx(hProcess, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_ALL))
{
for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
_tprintf(TEXT("%s (0x%08X)
"), szModName, hMods[i]);
}
}
}
return cbNeeded / sizeof(HMODULE);
}
int main()
{
HANDLE hProcess;
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
{
return 1;
}
cProcesses = cbNeeded / sizeof(DWORD);
for (i = 0; i < cProcesses; i++)
{
if (aProcesses[i] != 0)
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
if (hProcess != NULL)
{
TCHAR szProcessName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, NULL, szProcessName, sizeof(szProcessName) / sizeof(TCHAR)))
{
_tprintf(TEXT("
Process
============
"));
_tprintf(TEXT("Process ID: %u
"), aProcesses[i]);
_tprintf(TEXT("Process Name: %s
"), szProcessName);
_tprintf(TEXT("
Modules
============
"));
GetProcessModulesEx(hProcess);
}
CloseHandle(hProcess);
}
}
}
return 0;
}
与前一个示例相比,这个示例代码的主要区别在于使用了 EnumProcessModulesEx 函数,该函数提供了更多选项和过滤功能。
3. Toolhelp32Snapshot
Toolhelp32Snapshot 是 Windows API 中一组帮助函数,该组函数可以为应用程序提供进程和模块信息。它使应用程序能够访问拥有更多特权级别的数据,并提供更高的可访问性和更精确的快照。例如,该 API 可以获取正在使用的 DLL 的位置,以及任何由该过程创建的线程、堆栈和插件信息。
下面是使用 Toolhelp32Snapshot 函数获取进程的所有模块名称的示例程序:
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
DWORD GetProcessModulesToolhelp(HANDLE hProcess)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(hProcess));
if (hSnapshot == INVALID_HANDLE_VALUE)
{
return 0;
}
MODULEENTRY32 me;
me.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(hSnapshot, &me))
{
CloseHandle(hSnapshot);
return 0;
}
do
{
_tprintf(TEXT("%s (0x%08X)
"), me.szModule, (DWORD)me.modBaseAddr);
} while (Module32Next(hSnapshot, &me));
CloseHandle(hSnapshot);
return 0;
}
int main()
{
HANDLE hProcess;
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
{
return 1;
}
cProcesses = cbNeeded / sizeof(DWORD);
for (i = 0; i < cProcesses; i++)
{
if (aProcesses[i] != 0)
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
if (hProcess != NULL)
{
TCHAR szProcessName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, NULL, szProcessName, sizeof(szProcessName) / sizeof(TCHAR)))
{
_tprintf(TEXT("
Process
============
"));
_tprintf(TEXT("Process ID: %u
"), aProcesses[i]);
_tprintf(TEXT("Process Name: %s
"), szProcessName);
_tprintf(TEXT("
Modules
============
"));
GetProcessModulesToolhelp(hProcess);
}
CloseHandle(hProcess);
}
}
}
return 0;
}
这个示例程序中使用了 Toolhelp32Snapshot 函数来获取进程的所有模块名称,与前面的两个示例函数相比,Toolhelp32Snapshot 函数更加简单、易于使用,但仍提供了有用的信息。
三种函数的比较
其中 EnumProcessModules 与 EnumProcessModules
