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

调用NtProtectVirtualMemory返回STATUS_ACCESS_VIOLATION求助

解决NtProtectVirtualMemory调用返回STATUS_ACCESS_VIOLATION的问题

核心问题:参数传递错误

你遇到的问题本质是NtProtectVirtualMemory的参数传递格式和VirtualProtect不同,导致函数内部访问非法内存地址,触发0xC0000005错误。

NtProtectVirtualMemory的第二、第三个参数是输入输出型指针参数:

  • 第二个参数BaseAddress是PVOID*(指向指针的指针),函数会根据页面对齐要求修改这个指针的值
  • 第三个参数RegionSize是PULONG(指向ULONG的指针),函数会调整这个值为页面大小的整数倍

而你的调用代码直接传递了sectionData->address(PVOID类型)和sectionData->size(ULONG类型),相当于把指针/数值本身当作指针地址传入,函数内部解引用时自然会访问非法内存。

修正后的代码示例

调整参数传递方式,传入指针的地址而非指针本身:

typedef NTSTATUS(__stdcall* tNtProtectVirtualMemory) (
    HANDLE, 
    IN OUT PVOID*, 
    IN OUT PULONG, 
    IN ULONG, 
    OUT PULONG
);

// ... 之前的模块获取代码保持不变 ...

// 准备输入输出参数(必须用变量存储,因为函数会修改它们)
PVOID baseAddr = sectionData->address;
ULONG regionSize = sectionData->size;
ULONG oldProtect;

NTSTATUS sts = OrigNtProtectVirtualMemory(
    (HANDLE)-1,          // 当前进程句柄,等效于NtCurrentProcess()
    &baseAddr,           // 传入指针的地址
    &regionSize,         // 传入大小变量的地址
    protect,
    &oldProtect
);

// 注意:调用后baseAddr和regionSize可能被系统调整为页面对齐的值

额外排查要点

  • 页面对齐检查:确保sectionData->address是页面对齐的(可以用VirtualQuery验证),如果不是,NtProtectVirtualMemory会自动调整baseAddr为最近的低地址页面,并扩大regionSize到包含整个页面范围。
  • 内存有效性:确认sectionData->address指向的内存确实属于当前注入的进程,且是已分配的有效区域。
  • 位数兼容性:如果目标进程是64位,你的注入DLL必须也是64位;32位DLL注入64位进程会导致指针大小不匹配,同样触发访问错误。
  • 权限检查:当前进程上下文必须拥有修改该内存区域保护属性的权限(既然VirtualProtect能成功,这点应该没问题)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 12:00:23