> Windows Syscalls
ntoskrnl.exeT1106T1055T1068

NtAllocateUserPhysicalPages

Allocates physical memory pages for use with Address Windowing Extensions (AWE).

Prototype

NTSTATUS NtAllocateUserPhysicalPages(
  HANDLE      ProcessHandle,
  PULONG_PTR  NumberOfPages,
  PULONG_PTR  UserPfnArray
);

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle to the process that will own the physical pages. Usually NtCurrentProcess().
NumberOfPagesPULONG_PTRin/outOn input: number of physical pages requested. On output: number actually allocated.
UserPfnArrayPULONG_PTRoutCaller-supplied array that receives an opaque page-frame identifier per allocated page.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x71win10-1507
Win10 16070x71win10-1607
Win10 17030x72win10-1703
Win10 17090x72win10-1709
Win10 18030x72win10-1803
Win10 18090x72win10-1809
Win10 19030x72win10-1903
Win10 19090x72win10-1909
Win10 20040x73win10-2004
Win10 20H20x73win10-20h2
Win10 21H10x73win10-21h1
Win10 21H20x73win10-21h2
Win10 22H20x73win10-22h2
Win11 21H20x73win11-21h2
Win11 22H20x73win11-22h2
Win11 23H20x73win11-23h2
Win11 24H20x75win11-24h2
Server 20160x71winserver-2016
Server 20190x72winserver-2019
Server 20220x73winserver-2022
Server 20250x75winserver-2025

Kernel module

ntoskrnl.exeNtAllocateUserPhysicalPages

Related APIs

AllocateUserPhysicalPagesFreeUserPhysicalPagesMapUserPhysicalPagesNtMapUserPhysicalPagesNtFreeUserPhysicalPagesVirtualAlloc

Syscall stub

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

Part of the Address Windowing Extensions (AWE) API family. AWE lets a process reserve a fixed virtual-address window and then map and remap arbitrary physical pages into it on demand — bypassing the Windows working-set and pagefile entirely. The opaque PFN values returned in UserPfnArray are *not* raw PFNs; they are kernel-side handles that can only be consumed by NtMapUserPhysicalPages and NtFreeUserPhysicalPages on the same process. The caller must hold **SeLockMemoryPrivilege** (usually only granted to LocalSystem and explicitly-configured service accounts), which is the practical gate that keeps AWE out of low-privilege malware.

Common malware usage

Three notable abuses. First, **non-pageable code stash**: pages allocated through AWE are never swapped to the pagefile, so a payload mapped through NtMapUserPhysicalPages stays out of pagefile.sys forever — defeating dead-disk forensics that recover RWX shellcode from a swap dump. Second, **kernel-R/W primitive amplification**: when paired with a vulnerable signed driver that exposes an arbitrary physical-memory read/write, the AWE PFNs let an exploit chain alias kernel-page contents into a user-mode window, turning a one-shot read into a persistent mapping. Third, **AV-evasion via unconventional VAD types**: AWE allocations show up as a `VadAwe` VAD subtype that some scanners ignore. SeLockMemoryPrivilege is the bottleneck; samples that need AWE usually pivot through a SYSTEM service first or chain a token-impersonation primitive that the privilege survives.

Detection opportunities

AWE usage outside SQL Server, Exchange, Oracle, and a handful of HPC frameworks is extremely rare. Event-log–based detection: monitor for `SeLockMemoryPrivilege` being added to a non-service account in Local Security Policy, and for token-adjustment events (Sysmon Event ID 4673 if subcategory auditing is enabled) on `SeLockMemoryPrivilege`. Kernel-side, the VAD-walk will surface `VadAwe` entries in unexpected processes (notepad.exe with an AWE region is wildly anomalous). EDRs with memory-scanner integration should treat MEM_PHYSICAL VirtualAlloc reservations in non-database processes as high-severity.

Direct syscall examples

cAWE allocation gated on SeLockMemoryPrivilege

// Enable SeLockMemoryPrivilege, then allocate physical pages and reserve a
// virtual address window for mapping.
#include <windows.h>

BOOL EnableLockMemoryPrivilege(void) {
    HANDLE hTok;
    TOKEN_PRIVILEGES tp;
    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hTok)) return FALSE;
    LookupPrivilegeValueA(NULL, "SeLockMemoryPrivilege", &tp.Privileges[0].Luid);
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    BOOL ok = AdjustTokenPrivileges(hTok, FALSE, &tp, 0, NULL, NULL) && GetLastError() == ERROR_SUCCESS;
    CloseHandle(hTok);
    return ok;
}

void awe_alloc(SIZE_T pages) {
    EnableLockMemoryPrivilege();

    ULONG_PTR  request = pages;
    ULONG_PTR *pfn     = (ULONG_PTR*)HeapAlloc(GetProcessHeap(), 0, pages * sizeof(ULONG_PTR));

    if (AllocateUserPhysicalPages(GetCurrentProcess(), &request, pfn)) {
        SIZE_T window = pages * 4096;
        PVOID  view   = VirtualAlloc(NULL, window,
                                     MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE);
        MapUserPhysicalPages(view, request, pfn);
        // 'view' now aliases the physical pages; remap on demand.
    }
}

asmx64 direct stub (Win11 24H2, SSN 0x75)

NtAllocateUserPhysicalPages PROC
    mov  r10, rcx
    mov  eax, 75h
    syscall
    ret
NtAllocateUserPhysicalPages ENDP

MITRE ATT&CK mappings

Last verified: 2026-05-20