一、Module32First、Module32Next
void Enum1()
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
if (hSnapshot == INVALID_HANDLE_VALUE)
return;
MODULEENTRY32W module{ 0 };
module.dwSize = sizeof(module);
BOOL bFound = Module32FirstW(hSnapshot, &module);
while (bFound)
{
std::wcout << module.szExePath << std::endl;
bFound = Module32Next(hSnapshot, &module);
}
CloseHandle(hSnapshot);
}
函数底层是通过搜索PEB.Ldr.InLoadOrderModuleList链来找到模块信息的。
二、EnumProcessModules
void Enum2()
{
HANDLE hProcess = GetCurrentProcess();
HMODULE hModules[1024];
DWORD cbNeeded = 0;
if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded))
{
for (auto i = 0u; i < (cbNeeded / sizeof(HMODULE)); i++)
{
WCHAR szFileName[MAX_PATH];
if (GetModuleFileNameExW(hProcess, hModules[i], szFileName, _countof(szFileName)))
{
std::wcout << szFileName << std::endl;
}
}
}
}
函数底层是通过搜索PEB.Ldr.InMemoryOrderModuleList链来找到模块信息的。
三、VirtualQuery
void Enum3()
{
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
ULONG_PTR ulStart = (ULONG_PTR)SystemInfo.lpMinimumApplicationAddress;
ULONG_PTR ulEnd = (ULONG_PTR)SystemInfo.lpMaximumApplicationAddress;
ULONG_PTR ulBaseAddress = ulStart;
MEMORY_BASIC_INFORMATION info{ 0 };
while (ulBaseAddress <= ulEnd)
{
if (VirtualQuery((PVOID)ulBaseAddress, &info, sizeof(info)) == sizeof(info))
{
if ((info.Type == MEM_IMAGE) && (info.AllocationBase == info.BaseAddress))
{
WCHAR szFileName[MAX_PATH];
if (GetModuleFileNameW((HMODULE)info.BaseAddress, szFileName, _countof(szFileName)) > 0)
{
std::wcout << szFileName << std::endl;
}
}
}
ulBaseAddress += 0x10000;
}
}
这个就是使用暴力搜索内存页的方法来定位模块信息,不依赖LDR链,VirtualQuery内部又会调用NtQueryVirtualMemory来取得内存页信息。这个方法效率低下,特别是在64位进程中,由于内存地址范围太大,需要很长时间去遍历完整个内存,所以一般情况下不使用这个方法。