调用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, // 传入指针的地址 ®ionSize, // 传入大小变量的地址 protect, &oldProtect ); // 注意:调用后baseAddr和regionSize可能被系统调整为页面对齐的值
额外排查要点
- 页面对齐检查:确保
sectionData->address是页面对齐的(可以用VirtualQuery验证),如果不是,NtProtectVirtualMemory会自动调整baseAddr为最近的低地址页面,并扩大regionSize到包含整个页面范围。 - 内存有效性:确认
sectionData->address指向的内存确实属于当前注入的进程,且是已分配的有效区域。 - 位数兼容性:如果目标进程是64位,你的注入DLL必须也是64位;32位DLL注入64位进程会导致指针大小不匹配,同样触发访问错误。
- 权限检查:当前进程上下文必须拥有修改该内存区域保护属性的权限(既然VirtualProtect能成功,这点应该没问题)。
内容的提问来源于stack exchange,提问作者CoreEntity
相关产品推荐
相关产品推荐

