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

手动调用NtAllocateVirtualMemory系统调用触发STATUS_ACCESS_VIOLATION错误求助

问题解决:Syscall调用NtAllocateVirtualMemory触发STATUS_ACCESS_VIOLATION

错误1:硬编码Syscall号不匹配

不同Windows版本(甚至同版本的不同补丁)里,NtAllocateVirtualMemory的Syscall编号可能变化。你直接写死eax=0x18,当前系统里这个编号大概率对应其他系统调用,参数不匹配直接导致内存访问违规。

解决方式:从ntdll.dll动态提取Syscall号,步骤如下:

  1. 用GetProcAddress获取NtAllocateVirtualMemory的函数地址
  2. 解析函数开头的指令:原生Nt函数开头一般是mov r10,rcx; mov eax,XX; syscall; ret,提取mov eax,XX里的XX作为Syscall号

示例代码:

#include <Windows.h>
#include <cstdint>

typedef NTSTATUS(WINAPI* pNtAllocateVirtualMemory)(
    HANDLE ProcessHandle,
    PVOID* BaseAddress,
    ULONG ZeroBits,
    PULONG RegionSize,
    ULONG AllocationType,
    ULONG Protect
);

uint32_t GetSyscallNumber(pNtAllocateVirtualMemory func) {
    uint8_t* funcBytes = reinterpret_cast<uint8_t*>(func);
    // 跳过mov r10,rcx指令(占3字节:0x4C 0x8B 0xD1)
    funcBytes += 3;
    // 读取mov eax,XX里的4字节编号(指令是0xB8后跟4字节数值)
    return *reinterpret_cast<uint32_t*>(funcBytes + 1);
}

错误2:参数传递非法指针

你在调用时把(PULONG)0x1000传给RegionSize参数,这相当于让系统去访问内存地址0x1000——这个地址通常是无效的,直接触发内存访问违规。

解决方式:定义一个ULONG变量存储要分配的内存大小,传递变量的地址:

int main()
{
    PVOID buffer = nullptr;
    ULONG allocSize = 0x1000; // 用变量存分配大小

    printf("[+] Calling NtAllocateVirtualMemory.\n");
    NTSTATUS status = SysNtAllocateVirtualMemory(GetCurrentProcess(), &buffer, 0, &allocSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READ);
    if (!NT_SUCCESS(status))
    {
        printf("[!] Unable to allocate memory: %x\n", status);
        return -1;
    }
    printf("Memory: %p\n", buffer);
    printf("[+] Call successful.\n");
}

配合动态Syscall号的汇编代码调整

如果坚持要用自定义Syscall函数,可以把动态获取的编号作为参数传入:

.code
    SysNtAllocateVirtualMemory PROC
        mov r10, rcx
        mov eax, edx ; 第二个参数传入Syscall号
        syscall
        ret
    SysNtAllocateVirtualMemory ENDP
END

对应的C++声明修改为:

extern "C" NTSTATUS SysNtAllocateVirtualMemory(HANDLE ProcessHandle, uint32_t syscallNum, PVOID * BaseAddress, ULONG ZeroBits, PULONG RegionSize, ULONG AllocationType, ULONG Protect);

调用时先获取Syscall号再传入即可。

额外建议

如果只是要在当前进程分配内存,完全可以直接调用VirtualAlloc,或者通过GetProcAddress调用ntdll.dll里的原生NtAllocateVirtualMemory函数,比自己写Syscall汇编稳定得多——管理员权限在这里没用,因为进程分配自己的内存不需要特殊权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 08:35:01