You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

x64 DLL注入Windows 10记事本成功但无预期弹窗问题

我帮你排查了代码里的几个关键问题,这就是为什么你的DLL注入后没弹窗的原因,以及对应的修复方案:

问题分析与修复方案

1. 最致命的错误:内存分配与写入的长度计算错误

Injector::inject函数中,你用sizeof(dllName) + 1来计算需要分配的内存大小,但dllName是一个const char*指针——在x64环境下,指针的大小是8字节,这显然远小于实际的DLL路径长度。这会导致只有路径的前几个字符被写入目标进程,LoadLibraryA根本找不到正确的DLL文件,自然不会触发弹窗。

修复代码

// 替换原来的VirtualAllocEx和WriteProcessMemory逻辑
size_t dllPathLen = strlen(dllName) + 1; // 计算实际字符串长度+终止符
LPVOID pDllPathAddr = VirtualAllocEx(hProcess, 0, dllPathLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!pDllPathAddr) {
    throw "Failed to allocate memory in the target process";
}

// 必须检查WriteProcessMemory的返回值,确保写入成功
BOOL writeSuccess = WriteProcessMemory(hProcess, pDllPathAddr, dllName, dllPathLen, NULL);
if (!writeSuccess) {
    throw "Failed to write DLL path to target process memory";
}

2. 检查LoadLibrary的实际执行结果

CreateRemoteThread成功只代表线程创建了,但LoadLibraryA可能执行失败(比如找不到DLL)。你需要在等待线程结束后,获取线程的退出码——它就是LoadLibraryA的返回值(非NULL才表示DLL加载成功):

添加代码

WaitForSingleObject(hRemoteThread, INFINITE);

// 获取LoadLibrary的执行结果
DWORD exitCode = 0;
GetExitCodeThread(hRemoteThread, &exitCode);
if (exitCode == NULL) {
    throw "LoadLibraryA failed to load the DLL";
}

// 别忘了关闭句柄,避免资源泄漏
CloseHandle(hRemoteThread);
CloseHandle(hProcess);

3. 降低OpenProcess的权限(最佳实践)

你用了PROCESS_ALL_ACCESS,这个权限过高,在Windows 10+下很容易因为UAC或进程权限问题导致OpenProcess失败(虽然你的情况里可能成功了,但这是不良实践)。替换为最小必要权限:

HANDLE hProcess = OpenProcess(
    PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 
    PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
    FALSE, 
    targetProcID
);

4. DllMain中调用UI函数的潜在风险

DLL_PROCESS_ATTACH时直接调用MessageBox可能会阻塞目标进程的主线程,甚至因为消息循环未就绪导致弹窗不显示。建议把UI逻辑放到单独的线程里:

修改DllMain代码

// 新增线程函数执行UI操作
DWORD WINAPI ShowMessageBoxes(LPVOID lpParam) {
    Share();
    Keep();
    return 0;
}

BOOLEAN WINAPI DllMain(HINSTANCE hDllHandle, DWORD nReason, LPVOID Reserved) {
    BOOLEAN bSuccess = TRUE;
    switch (nReason) {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls(hDllHandle);
            // 创建新线程执行弹窗逻辑,避免阻塞DllMain
            CreateThread(NULL, 0, ShowMessageBoxes, NULL, 0, NULL);
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return bSuccess;
}

5. 资源泄漏修复

getTargetProcessID函数中,CreateToolhelp32Snapshot返回的句柄没有关闭,会造成资源泄漏,需要添加关闭逻辑:

DWORD Injector::getTargetProcessID(const char* targetProcName) {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if (!hSnap) {
        throw "Snapshot tool failed to open";
    }

    DWORD ProcID = NULL;
    if (Process32First(hSnap, &entry)) {
        do {
            if (!strcmp(entry.szExeFile, targetProcName)) {
                ProcID = entry.th32ProcessID;
                break; // 找到目标进程后直接退出循环
            }
        } while (Process32Next(hSnap, &entry));
    } else {
        throw "No running processes found";
    }

    CloseHandle(hSnap); // 关闭快照句柄
    return ProcID;
}

验证步骤

  1. 修复后重新编译注入器和DLL;
  2. 运行注入器时尽量以管理员身份运行(如果目标记事本是管理员权限启动的);
  3. 可以打印fullname变量,确认DLL的绝对路径是正确的。

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

火山引擎 最新活动