CreateRemoteThread常失败的根本原因是权限与架构不匹配:必须启用SeDebugPrivilege调试权限,且注入器、DLL、目标进程三者架构(32/64位)严格一致;同时需精简OpenProcess权限、使用绝对路径、正确分配可执行内存并动态获取LoadLibraryA地址。

为什么直接调用 CreateRemoteThread 常失败?
多数人卡在这一步:调用 CreateRemoteThread 后返回 NULL,GetLastError() 是 ERROR_ACCESS_DENIED 或 ERROR_INVALID_PARAMETER。根本原因不是代码写错,而是权限和目标进程类型不匹配。
- 目标进程是 64 位时,32 位注入器无法加载 64 位 DLL(反之亦然),必须严格架构一致
- Windows 10+ 默认阻止低完整性进程向高完整性进程注入(UAC 提权后仍需
SeDebugPrivilege) -
VirtualAllocEx分配内存时若未指定PAGE_EXECUTE_READWRITE,后续CreateRemoteThread会因页保护失败 - 部分安全软件(如 Windows Defender、火绒)会拦截
OpenProcess对关键进程(如explorer.exe、lsass.exe)的访问
如何正确获取目标进程句柄并启用调试权限?
不能只靠 OpenProcess(PROCESS_ALL_ACCESS, ...) —— 大多数情况下它会失败,必须先提权再打开。
- 调用
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)获取当前进程令牌 - 用
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)查找SeDebugPrivilege的 LUID - 通过
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)启用该权限(注意tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED) - 之后再调用
OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwPID)—— 避免使用PROCESS_ALL_ACCESS,精简权限更稳定
LoadLibraryA 地址怎么找?硬编码会崩溃
不能写死 0x7ffa12345678 这类地址 —— 不同系统、不同版本的 kernel32.dll 基址完全不同,硬编码必然崩。
C++ Code Review Master
下载
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 用
GetModuleHandleA("kernel32.dll")在注入器进程中获取本地kernel32模块句柄 - 再用
GetProcAddress(hKernel32, "LoadLibraryA")得到本机LoadLibraryA地址 - 这个地址可直接传给
CreateRemoteThread—— Windows 允许跨进程调用系统 DLL 中的导出函数(只要目标进程已加载该 DLL,而几乎所有进程都加载了kernel32) - 注意:不要用
GetModuleHandleW+GetProcAddress获取LoadLibraryW,宽字符路径在远程线程中容易因编码或内存布局异常出错
DLL 路径字符串怎么安全写入目标进程?
远程内存里写入的路径字符串一旦含中文、空格或反斜杠错误,LoadLibraryA 就静默失败,且无日志可查。
立即学习“C++免费学习笔记(深入)”;
- 路径必须是绝对路径(如
"C:\temp\inject.dll"),相对路径在目标进程上下文中无意义 - 写入前用
VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)分配内存,大小按strlen(szDllPath) + 1计算,别漏掉结尾