> Windows Syscalls
ntoskrnl.exeT1055T1055.002T1620

NtAllocateVirtualMemory

Reserves, commits or both a region of virtual memory in a target process.

Prototype

NTSTATUS NtAllocateVirtualMemory(
  HANDLE    ProcessHandle,
  PVOID    *BaseAddress,
  ULONG_PTR ZeroBits,
  PSIZE_T   RegionSize,
  ULONG     AllocationType,
  ULONG     Protect
);

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle to the target process. Use NtCurrentProcess() ((HANDLE)-1) for self.
BaseAddressPVOID*in/outPointer to the requested base address. NULL lets the kernel choose. Updated on return.
ZeroBitsULONG_PTRinNumber of high-order zero bits in BaseAddress. Typically 0.
RegionSizePSIZE_Tin/outPointer to the desired size, rounded up to a page boundary on return.
AllocationTypeULONGinAllocation flags. MEM_COMMIT | MEM_RESERVE is the most common combination.
ProtectULONGinMemory protection constant, e.g. PAGE_READWRITE, PAGE_EXECUTE_READWRITE.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 19090x18win10-1909
Win10 20040x18win10-2004
Win10 20H20x18win10-20h2
Win10 21H10x18win10-21h1
Win10 21H20x18win10-21h2
Win10 22H20x18win10-22h2
Win11 21H20x18win11-21h2
Win11 22H20x18win11-22h2
Win11 23H20x18win11-23h2
Win11 24H20x18win11-24h2
Server 20190x18winserver-2019
Server 20220x18winserver-2022
Server 20250x18winserver-2025

Kernel module

ntoskrnl.exeNtAllocateVirtualMemory

Related APIs

VirtualAllocVirtualAllocExNtAllocateVirtualMemoryExNtProtectVirtualMemoryNtWriteVirtualMemoryNtFreeVirtualMemory

Syscall stub

4C 8B D1            mov r10, rcx
B8 18 00 00 00      mov eax, 0x18
F6 04 25 08 03 FE 7F 01   test byte ptr [0x7FFE0308], 1
75 03               jne short +3
0F 05               syscall
C3                  ret
CD 2E               int 2Eh
C3                  ret

Undocumented notes

The syscall number for NtAllocateVirtualMemory has been remarkably stable across Windows 10 1909 through Windows 11 24H2 — `0x18`. This is *not* the case for many adjacent syscalls (e.g. NtCreateThreadEx), which is exactly why dynamic resolution via Hell's Gate or Halo's Gate is preferred over hardcoded numbers when targeting multiple builds. The function dispatches through KiSystemServiceCopyEnd → MmAllocateVirtualMemory inside ntoskrnl.exe.

Common malware usage

Foundational for almost every shellcode loader: allocate RW or RWX memory in the current or a remote process, copy payload, then transition protection with NtProtectVirtualMemory. Used by Cobalt Strike beacon spawn, Sliver implants, classic process injection, and most off-the-shelf droppers. Combined with NtWriteVirtualMemory + NtCreateThreadEx it forms the canonical CreateRemoteThread-equivalent direct-syscall chain.

Cobalt StrikeSliverQakbotTrickBotEmotetIcedID

Detection opportunities

On its own, NtAllocateVirtualMemory is *extremely* common in legitimate software and not a useful signal. What matters is *how* and *where* it is called: RWX allocations, allocations in remote processes, and short-lived RW→RX→Execute sequences. EDRs hook NtAllocateVirtualMemory in ntdll.dll; direct syscalls bypass that hook but leave kernel-visible artifacts (VAD entries, ETW Threat Intelligence events, PsSetCreateProcessNotifyRoutineEx callbacks for remote thread creation). Sysmon Event ID 8 (CreateRemoteThread) and Event ID 10 (ProcessAccess with VM_OPERATION/VM_WRITE) are the most useful blue-team telemetry — they fire on the *consequences* of the allocation, not the allocation itself.

Direct syscall examples

asmx64 direct stub

; Direct syscall stub for NtAllocateVirtualMemory (SSN 0x18, Win10 1909+)
NtAllocateVirtualMemory PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 18h          ; SSN
    syscall
    ret
NtAllocateVirtualMemory ENDP

cHell's Gate dynamic lookup

// Resolve SSN dynamically from ntdll export at runtime — survives KB updates.
DWORD GetSyscallNumber(PVOID pNtFunction) {
    BYTE* p = (BYTE*)pNtFunction;
    if (p[0] == 0x4C && p[1] == 0x8B && p[2] == 0xD1 && p[3] == 0xB8) {
        return *(DWORD*)(p + 4);
    }
    return 0;
}

// usage
HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
DWORD ssn = GetSyscallNumber(GetProcAddress(hNtdll, "NtAllocateVirtualMemory"));

rustwindows-sys + naked asm

// Cargo: windows-sys = "0.59"  (Win32_Foundation, Win32_System_Memory)
use std::arch::asm;

#[unsafe(naked)]
unsafe extern "system" fn nt_alloc_virtual_memory_stub() {
    asm!(
        "mov r10, rcx",
        "mov eax, 0x18",
        "syscall",
        "ret",
        options(noreturn),
    );
}

MITRE ATT&CK mappings

Last verified: 2026-05-20