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

Windows进程DLL注入成功后调用导出函数失败的原因排查

DLL注入后调用导出函数提示不存在的问题排查

我尝试将DLL注入Windows进程(如notepad.exe),注入操作能正常完成,但调用已注入DLL的导出函数时,系统提示该进程中不存在此函数。以下是注入器代码、DLL代码及相关截图,求排查原因。

注入器代码

#include <Windows.h>
#include <stdio.h>
#include <cassert>
#include <TlHelp32.h> // 用于枚举远程进程中的模块

// 获取远程加载模块的句柄
HMODULE GetRemoteModuleHandle(HANDLE hProcess, const wchar_t* moduleName) {
    HMODULE hModule = nullptr;
    MODULEENTRY32 me = { sizeof(me) };

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(hProcess));
    if (hSnapshot == INVALID_HANDLE_VALUE)
        return nullptr;

    if (Module32First(hSnapshot, &me)) {
        do {
            if (_wcsicmp(me.szModule, moduleName) == 0) {
                hModule = me.hModule;
                break;
            }
        } while (Module32Next(hSnapshot, &me));
    }

    CloseHandle(hSnapshot);
    return hModule;
}

int main(int argc, const char* argv[]) {
    if (argc < 3) {
        printf("用法: Inyector <pid> <dllPath>\n");
        return 0;
    }

    auto pid = atoi(argv[1]);

    // 打开目标进程
    HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD, FALSE, pid);
    if (!hProcess) {
        printf("打开进程失败 (%u)\n", GetLastError());
        return 1;
    }

    // 在目标进程中分配内存
    auto p = VirtualAllocEx(hProcess, nullptr, 1 << 12, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    assert(p);

    // 将DLL路径写入目标进程内存
    WriteProcessMemory(hProcess, p, argv[2], strlen(argv[2]) + 1, nullptr);

    // 创建远程线程调用LoadLibraryA加载DLL
    auto hThread = CreateRemoteThread(hProcess, nullptr, 0,
        (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA"), p, 0, nullptr);

    assert(hThread);
    WaitForSingleObject(hThread, INFINITE);

    // 获取远程进程中加载的模块句柄
    HMODULE remoteModule = GetRemoteModuleHandle(hProcess, L"mydll.dll");
    if (!remoteModule) {
        printf("错误: 无法找到远程模块\n");
        return 1;
    }

    // 获取本地DLL中导出函数的地址
    auto funcAddr = (LPVOID)GetProcAddress(GetModuleHandle(L"mydll.dll"), "MyFunc");
    if (!funcAddr) {
        printf("错误: 无法找到函数 'MyFunc'\n");
        return 1;
    }

    // 计算远程进程中函数的地址
    uintptr_t remoteFuncAddr = (uintptr_t)funcAddr - (uintptr_t)GetModuleHandle(L"mydll.dll") + (uintptr_t)remoteModule;

    // 创建远程线程调用MyFunc
    auto hFuncThread = CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)remoteFuncAddr, nullptr, 0, nullptr);
    if (!hFuncThread) {
        printf("错误: 无法执行远程函数 (%u)\n", GetLastError());
    }
    else {
        printf("远程函数执行成功.\n");
    }

    // 清理资源
    CloseHandle(hFuncThread);
    CloseHandle(hThread);
    CloseHandle(hProcess);

    return 0;
}

DLL代码

#include <windows.h>


// 导出函数
extern "C" __declspec(dllexport) void MyFunc(long parm1) {

    for (int i = 1; i <= 10; i++) {
        // 循环弹出消息框
        MessageBox(
            NULL,                                // 父窗口(无)
            L"这是测试消息",                     // 消息文本
            L"MessageBox循环",                   // 标题
            MB_OK | MB_ICONINFORMATION           // OK按钮+信息图标
        );
    }

}

// DLL入口函数(可选)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

相关截图

注入流程与导出函数调用截图
Visual Studio工具查看导出函数名称截图


可能的原因及解决方案

  • 函数参数不匹配:
    DLL中MyFunc定义需要一个long类型参数,但注入器调用时传入的是nullptr,未提供对应参数。这种参数不匹配可能触发进程异常,导致系统误报“函数不存在”。需确保调用时传入正确参数,比如修改CreateRemoteThread的参数传递部分:

    // 分配内存存储参数
    long param = 123;
    LPVOID pParam = VirtualAllocEx(hProcess, nullptr, sizeof(long), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    WriteProcessMemory(hProcess, pParam, &param, sizeof(long), nullptr);
    // 创建线程时传入参数地址
    auto hFuncThread = CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)remoteFuncAddr, pParam, 0, nullptr);
    
  • 导出函数名称修饰问题:
    尽管使用了extern "C",仍可能因编译选项问题导致函数名被修饰。从截图确认导出表中的函数名是否为MyFunc,建议添加.def文件强制指定导出名称:
    创建mydll.def文件,内容如下:

    LIBRARY "mydll"
    EXPORTS
        MyFunc @1
    

    将该文件加入DLL项目编译,确保函数以纯名称导出。

  • 位数不匹配:
    注入器、目标进程、DLL的编译位数必须一致(同为32位或64位)。如果32位注入器操作64位进程,CreateToolhelp32Snapshot无法正确枚举模块,导致远程模块基地址计算错误,进而函数地址无效。

  • DLL版本不一致:
    注入器本地加载的DLL与注入到远程进程的DLL如果不是同一版本,会导致函数偏移计算错误。需确保本地和远程使用的是同一个DLL文件。

  • 权限或进程保护:
    目标进程可能有反注入保护,或注入器未以管理员身份运行,导致远程线程无法执行。尝试提升注入器权限,或更换无保护的测试进程(如notepad.exe)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:24:51