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; }
验证步骤
- 修复后重新编译注入器和DLL;
- 运行注入器时尽量以管理员身份运行(如果目标记事本是管理员权限启动的);
- 可以打印
fullname变量,确认DLL的绝对路径是正确的。
内容的提问来源于stack exchange,提问作者Lior Levin




