> Windows Syscalls
ntoskrnl.exeT1055T1620T1106

NtAllocateVirtualMemoryEx

Reserves or commits virtual memory with extended parameters (preferred NUMA node, CFG, address requirements).

Prototype

NTSTATUS NtAllocateVirtualMemoryEx(
  HANDLE                 ProcessHandle,
  PVOID                 *BaseAddress,
  PSIZE_T                RegionSize,
  ULONG                  AllocationType,
  ULONG                  PageProtection,
  PMEM_EXTENDED_PARAMETER ExtendedParameters,
  ULONG                  ExtendedParameterCount
);

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.
RegionSizePSIZE_Tin/outPointer to the desired size, rounded up to a page boundary on return.
AllocationTypeULONGinAllocation flags. MEM_COMMIT | MEM_RESERVE most common; MEM_RESERVE_PLACEHOLDER and MEM_REPLACE_PLACEHOLDER supported.
PageProtectionULONGinMemory protection constant. PAGE_TARGETS_INVALID can be OR-ed to bypass CFG for the allocated pages.
ExtendedParametersPMEM_EXTENDED_PARAMETERinOptional array of MEM_EXTENDED_PARAMETER entries (NUMA node, address requirements, attribute flags).
ExtendedParameterCountULONGinNumber of entries in ExtendedParameters, or 0 if not used.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 18030x74win10-1803
Win10 18090x74win10-1809
Win10 19030x74win10-1903
Win10 19090x74win10-1909
Win10 20040x76win10-2004
Win10 20H20x76win10-20h2
Win10 21H10x76win10-21h1
Win10 21H20x76win10-21h2
Win10 22H20x76win10-22h2
Win11 21H20x76win11-21h2
Win11 22H20x76win11-22h2
Win11 23H20x76win11-23h2
Win11 24H20x78win11-24h2
Server 20190x74winserver-2019
Server 20220x76winserver-2022
Server 20250x78winserver-2025

Kernel module

ntoskrnl.exeNtAllocateVirtualMemoryEx

Related APIs

VirtualAlloc2VirtualAlloc2FromAppMapViewOfFile3NtAllocateVirtualMemoryNtMapViewOfSectionExNtProtectVirtualMemory

Syscall stub

4C 8B D1            mov r10, rcx
B8 78 00 00 00      mov eax, 0x78
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

NtAllocateVirtualMemoryEx was introduced in Windows 10 1803 to back the new VirtualAlloc2 / VirtualAlloc2FromApp APIs. Its SSN has shifted three times within the supported window — 0x74 on RS4–19H2, 0x76 from 20H1 through 23H2, and 0x78 on 24H2 / Server 2025 — so dynamic resolution (Hell's Gate / Halo's Gate / Tartarus' Gate) is mandatory when targeting more than one channel. Compared with NtAllocateVirtualMemory it adds the MEM_EXTENDED_PARAMETER array and supports placeholder allocations (used by Windows for sparse mappings and memfd-style file mappings).

Common malware usage

Increasingly preferred over the classic NtAllocateVirtualMemory for three reasons. (1) **Less-hooked surface**: many EDRs only patch NtAllocateVirtualMemory, leaving the Ex variant uninstrumented; recent BumbleBee, IcedID, and Latrodectus loaders explicitly call the Ex path for this reason. (2) **PAGE_TARGETS_INVALID** marks the new region as not-a-valid-indirect-call-target under CFG, then the loader switches it to PAGE_EXECUTE_READ; this is the documented way to bypass CFG when the host enables it. (3) **MEM_EXTENDED_PARAMETER with MemExtendedParameterAddressRequirements** lets the implant request an allocation at a precise high-entropy address, useful for spoofing module-like base addresses in remote processes.

Detection opportunities

Cross-process allocations via the Ex path with non-zero ExtendedParameterCount are uncommon outside graphics drivers and AppContainer brokers — alertable. ETW Threat Intelligence's `EtwTiLogAllocExecVm` callback fires on the Ex path as well as the classic call. Sysmon does not natively distinguish the two; correlation with NtWriteVirtualMemory / NtCreateThreadEx remains the cheapest behavioural signal. EDR vendors that hook only NtAllocateVirtualMemory will miss this entirely — verify hook coverage on both names during purple-team work.

Direct syscall examples

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtAllocateVirtualMemoryEx (SSN 0x78 on 24H2/2025)
NtAllocateVirtualMemoryEx PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 78h          ; SSN — RESOLVE DYNAMICALLY for multi-build targeting
    syscall
    ret
NtAllocateVirtualMemoryEx ENDP

cCFG bypass via PAGE_TARGETS_INVALID

// Allocate RWX page that CFG will not accept as a valid indirect call target.
// Then flip to RX before calling — defeats CFG-only mitigations.
#include <windows.h>

typedef NTSTATUS (NTAPI *pNtAllocateVirtualMemoryEx)(
    HANDLE, PVOID*, PSIZE_T, ULONG, ULONG, PMEM_EXTENDED_PARAMETER, ULONG);

PVOID  base = NULL;
SIZE_T size = 0x1000;
pNtAllocateVirtualMemoryEx Fn = (pNtAllocateVirtualMemoryEx)
    GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtAllocateVirtualMemoryEx");
Fn((HANDLE)-1, &base, &size,
   MEM_COMMIT | MEM_RESERVE,
   PAGE_EXECUTE_READWRITE | PAGE_TARGETS_INVALID,
   NULL, 0);

rustVirtualAlloc2 wrapper

// Cargo: windows-sys = "0.59" (Win32_System_Memory)
use windows_sys::Win32::System::Memory::{
    VirtualAlloc2, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE,
};

pub unsafe fn alloc_rwx(size: usize) -> *mut core::ffi::c_void {
    VirtualAlloc2(0, core::ptr::null_mut(), size,
                  MEM_COMMIT | MEM_RESERVE,
                  PAGE_EXECUTE_READWRITE,
                  core::ptr::null_mut(), 0)
}

MITRE ATT&CK mappings

Last verified: 2026-05-20