You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用VirtualAllocEx返回MEM_FREE/PAGE_NO_ACCESS内存的问题排查

问题分析与解决方案

你的核心问题是未严格遵循x64 Windows调用约定,导致VirtualAllocEx的第5个参数flProtect传递错误,进而出现内存属性不符、VirtualProtectEx调用失败的异常。

关键错误点

x64 Windows调用约定明确要求:

  1. 调用任何API前,RSP必须保持16字节对齐(call指令会压入8字节返回地址,调用后RSP会变为8字节对齐,被调用函数会自行调整回16字节对齐)。
  2. 无论参数数量多少,调用者必须为被调用者预留32字节的阴影空间(Shadow Space),供被调用函数临时保存RCX/RDX/R8/R9寄存器。
  3. 第5个及以后的参数,需放在阴影空间之后的栈位置(按8字节对齐传递,即使参数是DWORD类型)。

你的代码直接操作[rsp+20h]传递flProtect,既未预留阴影空间,也未保证RSP对齐,导致VirtualAllocEx读取到错误的参数值——实际传递的可能不是0x40,而是栈上的随机数据,最终导致内存页属性不符合预期。

修复后的汇编代码

以下是符合调用约定的正确实现,使用栈帧管理栈空间避免计算错误:

push rbp
mov rbp, rsp          ; 构建栈帧,确保RSP对齐16字节

sub rsp, 48           ; 预留32字节阴影空间 + 8字节第5个参数空间(48是16的倍数,保持对齐)

mov rcx, rax          ; 1st参数:hProcess(OpenProcess返回的句柄)
xor rdx, rdx          ; 2nd参数:lpAddress = NULL
mov r8, 01000h        ; 3rd参数:dwSize = 0x1000
mov r9, 03000h        ; 4th参数:flAllocationType = MEM_COMMIT | MEM_RESERVE
mov qword ptr [rbp-48], 040h ; 5th参数:flProtect = PAGE_EXECUTE_READWRITE(放在阴影空间后)

mov rax, [r15+90h]    ; 获取VirtualAllocEx函数指针
call rax              ; 调用API,返回地址存入RAX

mov r13, rax          ; 保存分配的内存地址

add rsp, 48           ; 恢复栈空间
pop rbp               ; 销毁栈帧

额外验证步骤

  1. 确认函数指针有效性:用Windbg查看[r15+90h]指向的地址,是否为kernel32!VirtualAllocEx的正确入口。
  2. 检查栈对齐:调用VirtualAllocEx前,执行r rsp命令确认RSP值的最后4位为0(16字节对齐)。
  3. 验证参数传递:调用前用dq rsp L10查看栈空间,确认flProtect参数(0x40)出现在正确位置。

关于VirtualProtectEx的补充说明

之前的内存分配参数错误,导致实际分配的内存可能处于未正确提交或权限不符的状态,进而触发VirtualProtectEx的访问拒绝错误。修复VirtualAllocEx的调用后,该问题会随之解决。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:55:59