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

为什么直接调用 CreateRemoteThread 常失败?
多数人卡在这步:调用 CreateRemoteThread 返回 NULL,GetLastError() 是 ERROR_ACCESS_DENIED 或 ERROR_INVALID_PARAMETER。根本原因不是代码写错,而是权限和目标进程状态不匹配。
关键点:
- 调用进程必须启用
SE_DEBUG_NAME权限(用OpenProcessToken+AdjustTokenPrivileges) - 目标进程不能是保护进程(如 Chrome、Edge、杀软主进程),Windows 10/11 对
Protected Process Light有严格限制 -
CreateRemoteThread的第三个参数(起始地址)必须是目标进程中已加载模块里的函数地址,比如LoadLibraryA,不能传自己进程的地址 - DLL 路径字符串必须是目标进程能访问的路径(推荐绝对路径,且目标进程有读取权限;不要用相对路径或当前目录)
怎么让 LoadLibraryA 在远程进程里执行?
核心是把 DLL 路径写入目标进程内存,再让 LoadLibraryA 读它。不是“复制 DLL 文件”,而是“注入加载指令”。
实操要点:
- 用
VirtualAllocEx在目标进程申请可读写内存(PAGE_READWRITE) - 用
WriteProcessMemory把 DLL 路径字符串(ANSI 格式)写进去 - 用
GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA")获取本机LoadLibraryA地址 —— 这个地址在目标进程的kernel32.dll中大概率相同(ASLR 关闭时 100% 相同;开启时需用EnumProcessModules+GetModuleInformation算偏移) - 最后调用
CreateRemoteThread,参数:hProcess、NULL、lpStartAddr(即LoadLibraryA地址)、lpParameter(即上面写入的路径地址)、0、&tid
64 位进程注入 32 位 DLL 会怎样?
直接失败,CreateRemoteThread 返回 NULL,GetLastError() 通常是 ERROR_INVALID_PARAMETER。x64 和 x86 是完全隔离的地址空间,不能混用。
必须严格匹配:
- 注入器(你的程序)架构 = 目标进程架构(查
IsWow64Process只能辅助判断,最准是用GetNativeSystemInfo对比目标进程的PROCESS_BASIC_INFORMATION) - 要注入的 DLL 必须和目标进程位数一致(32 位进程只能加载 32 位 DLL)
- 如果你的注入器是 64 位,想注入 32 位进程,必须另起一个 32 位子进程来执行注入逻辑(常见方案:用
Wow64DisableWow64FsRedirection不起作用,别试)
注入后 DLL 没反应?检查这三件事
常见假阴性:看起来没报错,但 DLL 的 DllMain 没执行,或者执行了但没效果。
优先排查:
-
DllMain里不能调用LoadLibrary、WaitForSingleObject、MessageBoxA等可能触发同步或加载的 API(会死锁) - 确保 DLL 编译时关闭了
/DELAYLOAD,延迟加载在远程进程里大概率失败(找不到导入表解析器) - 用
Process Hacker或VMMap查看目标进程内存,确认 DLL 是否真被加载到模块列表里(路径是否显示为预期值);如果模块名是???或路径乱码,说明WriteProcessMemory写入失败或路径含宽字符
真正麻烦的是绕过 EDR 的检测逻辑 —— 那已经超出 CreateRemoteThread 范畴,涉及 APC 注入、反射式加载、SetThreadContext 修改 RIP 等,而且每家产品规则不同,没有通用解法。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











