欢迎访问宙启技术站
智能推送

【API】获取进程的所有模块名

发布时间:2023-05-14 02:08:12

在 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