VirtualAllocEx调用失败常见原因包括:目标进程句柄权限不足(需PROCESS_VM_OPERATION | PROCESS_VM_WRITE)、32/64位架构不匹配、UAC提权未生效、内存页属性被CFG/HVCI拦截;成功后WriteProcessMemory写入失败多因shellcode长度误算或地址截断。

VirtualAllocEx调用失败返回NULL,常见原因有哪些
多数情况下不是权限问题,而是目标进程句柄没开对。必须用 OpenProcess 获取 PROCESS_VM_OPERATION | PROCESS_VM_WRITE 权限(PROCESS_ALL_ACCESS 不是万能的,尤其在低完整性进程里会静默失败)。如果目标进程是 64 位而当前程序是 32 位(或反之),VirtualAllocEx 会直接返回 NULL,且 GetLastError() 可能返回 ERROR_PARTIAL_COPY 或 ERROR_INVALID_PARAMETER —— 这其实是架构不匹配的典型信号。
- 确保编译目标与目标进程一致:x64 程序操作 x64 进程,x86 程序只能操作 x86 进程
- 检查
OpenProcess返回值是否为INVALID_HANDLE_VALUE,别只看NULL - UAC 提权未生效时,即使以管理员运行,句柄也可能只有有限权限;可用
IsWow64Process验证进程模式
申请内存时指定 MEM_COMMIT | MEM_RESERVE 和 PAGE_EXECUTE_READWRITE 的实际含义
MEM_COMMIT | MEM_RESERVE 是最常用组合,但要注意:只用 MEM_RESERVE 不会分配物理页,后续仍需 VirtualAllocEx 再次调用提交,而远程注入通常一步到位。页保护属性选 PAGE_EXECUTE_READWRITE 是为了后续写入 shellcode 并执行;但 Windows 10 1709+ 启用 CFG 和 HVCI 后,该属性可能被拦截——此时 VirtualAllocEx 仍成功,但后续 CreateRemoteThread 会触发异常或被杀软终止。
- 若只需写入数据(如配置字符串),用
PAGE_READWRITE更安全,避免触发 EDR 行为检测 -
PAGE_EXECUTE_READ无法写入,PAGE_EXECUTE_WRITECOPY在远程场景基本无效(写时复制机制不跨进程) - 某些沙箱或加固环境会禁用
EXECUTE类属性,可先试PAGE_READWRITE+VirtualProtectEx升级权限(但多一次系统调用)
为什么 VirtualAllocEx 成功后,WriteProcessMemory 却写不进数据
最常被忽略的是地址对齐和缓冲区长度:目标地址必须按系统分配粒度对齐(通常是 64KB),但 VirtualAllocEx 返回的地址天然满足;真正出问题的是传给 WriteProcessMemory 的 lpBuffer 长度——如果 shellcode 含嵌入式 null 字节,而误用 strlen 计算长度,就会提前截断。
- 永远用
sizeof(shellcode)或显式字节数,而非字符串函数 - 检查
WriteProcessMemory返回值和lpNumberOfBytesWritten,它可能小于请求长度(例如目标内存被部分锁定) - 若目标进程启用了 SMEP/SMAP(现代 CPU 常见),往用户态内存写内核 shellcode 会失败,但错误表现仍是写入长度不匹配
32 位与 64 位进程间指针传递的陷阱
在 64 位系统上,VirtualAllocEx 返回的地址是 64 位整数,如果用 DWORD(32 位)变量接收,高位会被截断,导致后续所有操作指向非法地址。C++ 中必须用 LPVOID 或 uintptr_t 保存该地址,并确保所有相关 API 调用(如 CreateRemoteThread)参数类型匹配。
- 不要把
VirtualAllocEx返回值强制转成DWORD或int - 使用
static_cast保持类型安全,而非 C 风格强转(addr) - 若通过 DLL 注入,注意导出函数指针在 32/64 位下大小不同,不能硬编码偏移
远程内存分配本身不难,难的是每一步都依赖前一步的精确状态:句柄权限、架构匹配、地址类型、页属性、写入长度——漏掉任意一个,都会让整个链路在无声中失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











