You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在通过CreateProcess创建的挂起进程中查找LoadLibrary地址?

在挂起进程中查找LoadLibrary函数地址的实现方法

核心思路

Windows系统中,LoadLibrary(实际对应LoadLibraryA或LoadLibraryW宏)是kernel32.dll导出的函数,所有Windows进程都会加载kernel32.dll。要获取目标进程中该函数的地址,需按以下步骤操作:

  • 打开目标进程并获取足够访问权限
  • 枚举目标进程已加载模块,定位kernel32.dll的基地址
  • 解析kernel32.dll的PE结构,遍历导出表找到LoadLibrary的地址

实现代码

以下是接收PROCESS_INFORMATION参数的函数实现:

#include <windows.h>
#include <psapi.h>
#include <tchar.h>

// 获取目标进程中LoadLibraryA的地址
FARPROC GetRemoteLoadLibraryAddress(const PROCESS_INFORMATION& pi)
{
    if (pi.hProcess == NULL)
        return NULL;

    // 提升进程权限以访问目标进程
    HANDLE hToken;
    if (!OpenProcessToken(pi.hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
        return NULL;

    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 1;
    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
    CloseHandle(hToken);

    // 枚举进程模块,找到kernel32.dll的基地址
    HMODULE hMods[1024];
    DWORD cbNeeded;
    if (!EnumProcessModules(pi.hProcess, hMods, sizeof(hMods), &cbNeeded))
        return NULL;

    HMODULE hKernel32 = NULL;
    TCHAR szModName[MAX_PATH];
    for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
    {
        if (GetModuleFileNameEx(pi.hProcess, hMods[i], szModName, MAX_PATH))
        {
            TCHAR* pFileName = _tcsrchr(szModName, _T('\\'));
            if (pFileName && _tcsicmp(pFileName + 1, _T("kernel32.dll")) == 0)
            {
                hKernel32 = hMods[i];
                break;
            }
        }
    }

    if (!hKernel32)
        return NULL;

    // 读取kernel32.dll的DOS头
    IMAGE_DOS_HEADER dosHeader;
    if (!ReadProcessMemory(pi.hProcess, hKernel32, &dosHeader, sizeof(dosHeader), NULL))
        return NULL;

    // 读取NT头
    IMAGE_NT_HEADERS ntHeaders;
    LPVOID pNtHeaders = (LPVOID)((DWORD_PTR)hKernel32 + dosHeader.e_lfanew);
    if (!ReadProcessMemory(pi.hProcess, pNtHeaders, &ntHeaders, sizeof(ntHeaders), NULL))
        return NULL;

    // 读取导出表
    IMAGE_EXPORT_DIRECTORY exportDir;
    LPVOID pExportDir = (LPVOID)((DWORD_PTR)hKernel32 + ntHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    if (!ReadProcessMemory(pi.hProcess, pExportDir, &exportDir, sizeof(exportDir), NULL))
        return NULL;

    // 读取导出函数的名称表、地址表、序号表
    DWORD* pNames = (DWORD*)((DWORD_PTR)hKernel32 + exportDir.AddressOfNames);
    DWORD* pAddresses = (DWORD*)((DWORD_PTR)hKernel32 + exportDir.AddressOfFunctions);
    WORD* pOrdinals = (WORD*)((DWORD_PTR)hKernel32 + exportDir.AddressOfNameOrdinals);

    // 遍历导出表查找LoadLibraryA
    FARPROC pLoadLibrary = NULL;
    for (DWORD i = 0; i < exportDir.NumberOfNames; i++)
    {
        CHAR szFuncName[256];
        LPVOID pFuncName = (LPVOID)((DWORD_PTR)hKernel32 + pNames[i]);
        if (!ReadProcessMemory(pi.hProcess, pFuncName, szFuncName, sizeof(szFuncName), NULL))
            continue;

        if (_stricmp(szFuncName, "LoadLibraryA") == 0)
        {
            DWORD dwFuncAddr = pAddresses[pOrdinals[i]];
            pLoadLibrary = (FARPROC)((DWORD_PTR)hKernel32 + dwFuncAddr);
            break;
        }
    }

    return pLoadLibrary;
}

关键注意事项

  • 编译时需链接psapi.lib(添加编译参数/link psapi.lib)
  • 代码中查找的是LoadLibraryA,若需宽字符版本LoadLibraryW,修改字符串比较部分即可
  • 所有跨进程内存操作必须使用ReadProcessMemory,因为目标进程内存空间与当前进程隔离
  • 若目标进程为64位,需确保代码使用DWORD_PTR等适配64位的指针类型

内容的提问来源于stack exchange,提问作者loaded_dypper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 03:17:15