Ⅰ. はじめに
タイトルの通り「C++でWindows上の特定プロセスの全モジュールを取得する方法」です。
Ⅱ. サンプルプログラム1(EnumProcessModulesExを使用する方法)
#include <windows.h>
#include <Psapi.h>
#include <iostream>
void ShowAllModules(uint32_t processId)
{
HMODULE hMods[1024];
auto processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
if (processHandle != nullptr)
{
DWORD cbNeeded;
if (EnumProcessModulesEx(processHandle, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_ALL))
{
for (uint32_t i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
wchar_t filePath[MAX_PATH];
if (GetModuleFileNameEx(processHandle, hMods[i], filePath, sizeof(filePath) / sizeof(wchar_t)))
{
std::wcout << "BaseAddress: 0x" << hMods[i] << std::endl;
std::wcout << "FilePath: " << filePath << std::endl;
}
}
}
CloseHandle(processHandle);
}
}
int main(void)
{
auto processId = 1234;
ShowAllModules(processId);
return 0;
}
#include <windows.h>
#include <Psapi.h>
#include <TlHelp32.h>
#include <iostream>
void ShowAllModules(uint32_t processId)
{
MODULEENTRY32 moduleEntry32 = { 0 };
auto processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
if (processHandle != nullptr)
{
auto hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processId);
if (hThreadSnap != INVALID_HANDLE_VALUE)
{
moduleEntry32.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(hThreadSnap, &moduleEntry32))
{
std::cout << "failed" << std::endl;
}
else
{
do
{
wchar_t filePath[MAX_PATH];
GetModuleFileNameEx(processHandle, moduleEntry32.hModule, filePath, MAX_PATH);
std::wcout << "BaseAddress: 0x" << moduleEntry32.modBaseAddr << std::endl;
std::wcout << "FilePath: " << filePath << std::endl;
} while (Module32Next(hThreadSnap, &moduleEntry32));
}
CloseHandle(hThreadSnap);
}
CloseHandle(processHandle);
}
}
int main(void)
{
auto processId = 1234;
ShowAllModules(processId);
return 0;
}
※対象がWOW64プロセスの場合はNtWow64QueryInformationProcess64を使用します。
#include <windows.h>
#include <winternl.h>
#include <iostream>
#pragma comment(lib, "ntdll.lib")
void ShowAllModules(uint32_t processId)
{
auto moduleHandle = LoadLibrary(L"ntdll.dll");
if (moduleHandle != nullptr)
{
auto pNtQueryInformationProcess = reinterpret_cast<decltype(&NtQueryInformationProcess)>(GetProcAddress(moduleHandle, "NtQueryInformationProcess"));
auto processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
if (processHandle != nullptr)
{
PROCESS_BASIC_INFORMATION pbi = { 0 };
if (NT_SUCCESS(pNtQueryInformationProcess(processHandle, PROCESSINFOCLASS::ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), nullptr)))
{
if (pbi.PebBaseAddress != nullptr)
{
PEB peb = { 0 };
ReadProcessMemory(processHandle, pbi.PebBaseAddress, &peb, sizeof(PEB), nullptr);
PEB_LDR_DATA pebLdrData = { 0 };
ReadProcessMemory(processHandle, peb.Ldr, &pebLdrData, sizeof(PEB_LDR_DATA), nullptr);
auto pModuleFirstEntry = pebLdrData.InMemoryOrderModuleList.Flink;
auto pModuleCurrentEntry = pebLdrData.InMemoryOrderModuleList.Flink;
do
{
auto pLdrDataTableEntry = CONTAINING_RECORD(pModuleCurrentEntry, LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::InMemoryOrderLinks);
LDR_DATA_TABLE_ENTRY ldrDataTableEntry = { 0 };
ReadProcessMemory(processHandle, pLdrDataTableEntry, &ldrDataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY), nullptr);
wchar_t str[MAX_PATH];
ReadProcessMemory(processHandle, ldrDataTableEntry.FullDllName.Buffer, &str, ldrDataTableEntry.FullDllName.Length, nullptr);
auto filePath = std::wstring(str, ldrDataTableEntry.FullDllName.Length / sizeof(wchar_t));
if (ldrDataTableEntry.DllBase != nullptr)
{
std::wcout << "BaseAddress: 0x" << ldrDataTableEntry.DllBase << std::endl;
std::wcout << "FilePath: " << filePath << std::endl;
}
pModuleCurrentEntry = ldrDataTableEntry.InMemoryOrderLinks.Flink;
} while (pModuleCurrentEntry != pModuleFirstEntry);
}
}
CloseHandle(processHandle);
}
FreeModule(moduleHandle);
}
}
int main(void)
{
auto processId = 1234;
ShowAllModules(processId);
return 0;
}
Ⅴ. 実行結果
BaseAddress: 0x00007FF699110000
FilePath: C:\WINDOWS\system32\notepad.exe
BaseAddress: 0x00007FFBCE1F0000
FilePath: C:\WINDOWS\SYSTEM32\ntdll.dll
BaseAddress: 0x00007FFBCE0F0000
FilePath: C:\WINDOWS\System32\KERNEL32.DLL
BaseAddress: 0x00007FFBCBC10000
FilePath: C:\WINDOWS\System32\KERNELBASE.dll
...
(以下省略)
Ⅵ. 留意点
- WOW64プロセスから64bitプロセスの情報を取得する事は出来ません。(参考1)
- NtQueryInformationProcessは非公開APIなので一般向きでは無いです。
- 私の環境では全て同じ実行結果が得られました。
使用しているAPIが異なる為実行結果が異なる可能性があります。
※一部モジュールが正しく取得できない等。