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

x86 DLL注入32位进程后DllMain未被调用的排查求助

32位DLL注入32位进程时DllMain未被调用的问题

我有一个编译为DLL的Qt GUI程序,x64编译时注入正常,但x86编译后注入32位进程时,其DllMain入口从未被调用。经过排查和重编译Qt源码,发现这可能不是Qt的问题——我用一个无依赖的纯DLL项目也复现了该问题:

#include <Windows.h>
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;
    }
    OutputDebugString(L"DllMain");
    return TRUE;
}

我的注入代码如下:

void injectDLL(DWORD processID, const QString& dllPath)
{
    // Open the target process.
    HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
    if (!processHandle)
    {
        qDebug() << "Failed to open process";
        return;
    }

    // Allocate memory in the target process.
    LPVOID remoteMemory = VirtualAllocEx(processHandle, NULL, dllPath.length(), MEM_COMMIT, PAGE_READWRITE);
    if (!remoteMemory)
    {
        qDebug() << "Failed to allocate memory in the remote process";
        CloseHandle(processHandle);
        return;
    }

    // Write the path of the DLL to be injected into the allocated memory in the target process.
    if (!WriteProcessMemory(processHandle, remoteMemory, dllPath.toStdWString().c_str(), dllPath.length() * sizeof(wchar_t), NULL))
    {
        qDebug() << "Failed to write path to the remote process memory";
        VirtualFreeEx(processHandle, remoteMemory, 0, MEM_RELEASE);
        CloseHandle(processHandle);
        return;
    }

    // Get the address of the LoadLibraryW function.
    LPVOID loadLibraryAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
    if (!loadLibraryAddress)
    {
        qDebug() << "Failed to get the address of LoadLibraryW";
        VirtualFreeEx(processHandle, remoteMemory, 0, MEM_RELEASE);
        CloseHandle(processHandle);
        return;
    }

    // Create a remote thread in the target process and pass the address of LoadLibraryW and the address of the allocated memory as arguments.
    HANDLE remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddress, remoteMemory, 0, NULL);
    if (!remoteThread)
    {
        qDebug() << "Failed to create a remote thread in the target process";
        VirtualFreeEx(processHandle, remoteMemory, 0, MEM_RELEASE);
        CloseHandle(processHandle);
        return;
    }

    // Wait for the remote thread to finish.
    WaitForSingleObject(remoteThread, INFINITE);

    // Cleanup.
    CloseHandle(remoteThread);
    VirtualFreeEx(processHandle, remoteMemory, 0, MEM_RELEASE);
    CloseHandle(processHandle);
}


int main()
{
    // wmplayer.exe pid
    injectDLL(51836, "D:/repos/Dll/Debug/Dll.dll");
    return 0;
}

测试注入的目标进程是32位的C:\Program Files (x86)\Windows Media Player\wmplayer.exe。使用VS22调试该DLL,但注入后DllMain从未被调用,OutputDebugString的内容也未输出。推测Qt DLL的问题与测试用纯DLL一致,请问哪里遗漏或操作错误?


解决方案

以下是几个关键问题点和修复方案:

1. 注入器与目标进程位数不匹配

注入器必须和目标进程位数完全一致:如果目标是32位进程,注入器必须编译为x86。x64编译的注入器无法正确调用32位进程的系统接口,内存地址空间和调用逻辑的差异会导致注入失败。

修复:将注入器项目的编译平台改为x86,重新编译后再执行注入操作。

2. 内存分配未预留字符串终止符

LoadLibraryW需要接收以NULL结尾的宽字符串,但当前VirtualAllocEx仅分配了等于路径长度的内存,没有预留sizeof(wchar_t)的空间存放终止符,会导致LoadLibraryW读取到垃圾数据,无法定位DLL路径。

修复:调整内存分配和写入的参数:

// 分配内存时预留终止符空间
LPVOID remoteMemory = VirtualAllocEx(processHandle, NULL, (dllPath.length() + 1) * sizeof(wchar_t), MEM_COMMIT, PAGE_READWRITE);

// 写入时包含终止符
size_t totalPathSize = (dllPath.length() + 1) * sizeof(wchar_t);
if (!WriteProcessMemory(processHandle, remoteMemory, dllPath.toStdWString().c_str(), totalPathSize, NULL))
{
    // 错误处理逻辑
}

3. 过高的进程权限请求

PROCESS_ALL_ACCESS权限要求过高,多数系统环境下无法获取,会导致OpenProcess失败或后续操作受限。建议使用最小必要权限集合。

修复:修改OpenProcess的权限参数:

HANDLE processHandle = OpenProcess(
    PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 
    PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, 
    FALSE, processID);

4. 未检查DLL加载结果

当前代码没有验证LoadLibraryW的执行结果,无法确认DLL是否被成功加载。可以通过GetExitCodeThread获取远程线程的返回值:

WaitForSingleObject(remoteThread, INFINITE);
DWORD exitCode = 0;
GetExitCodeThread(remoteThread, &exitCode);
if (exitCode == NULL)
{
    qDebug() << "LoadLibraryW调用失败,DLL未加载";
}

若返回值为NULL,说明LoadLibraryW执行失败,可进一步排查DLL路径是否正确、DLL是否存在缺失的依赖库。

5. 调试方式错误

调试DLL时,需将VS调试器附加到**目标进程(wmplayer.exe)**而非注入器。在DLL_PROCESS_ATTACH分支添加断点,注入完成后断点会触发。另外,OutputDebugString的输出需要通过DebugView等工具捕获,确保工具已监听目标进程的调试输出。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:08:08