> Windows Syscalls
ntoskrnl.exeT1106T1055T1027

NtMapUserPhysicalPages

Mapea páginas físicas asignadas vía AWE en una ventana de direcciones virtuales previamente reservada.

Prototipo

NTSTATUS NtMapUserPhysicalPages(
  PVOID       VirtualAddress,
  ULONG_PTR   NumberOfPages,
  PULONG_PTR  UserPfnArray
);

Argumentos

NameTypeDirDescription
VirtualAddressPVOIDinBase de una ventana de direcciones virtuales reservada con MEM_RESERVE | MEM_PHYSICAL.
NumberOfPagesULONG_PTRinNúmero de páginas a mapear. No debe exceder el tamaño de la ventana reservada.
UserPfnArrayPULONG_PTRinArreglo de identificadores de página opacos de NtAllocateUserPhysicalPages, o NULL para desmapear.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070x101win10-1507
Win10 16070x106win10-1607
Win10 17030x10Awin10-1703
Win10 17090x10Bwin10-1709
Win10 18030x10Cwin10-1803
Win10 18090x10Dwin10-1809
Win10 19030x10Ewin10-1903
Win10 19090x10Ewin10-1909
Win10 20040x113win10-2004
Win10 20H20x113win10-20h2
Win10 21H10x113win10-21h1
Win10 21H20x114win10-21h2
Win10 22H20x114win10-22h2
Win11 21H20x11Awin11-21h2
Win11 22H20x11Bwin11-22h2
Win11 23H20x11Bwin11-23h2
Win11 24H20x11Dwin11-24h2
Server 20160x106winserver-2016
Server 20190x10Dwinserver-2019
Server 20220x119winserver-2022
Server 20250x11Dwinserver-2025

Módulo del kernel

ntoskrnl.exeNtMapUserPhysicalPages

APIs relacionadas

MapUserPhysicalPagesMapUserPhysicalPagesScatterAllocateUserPhysicalPagesNtAllocateUserPhysicalPagesNtFreeUserPhysicalPagesVirtualAlloc

Stub del syscall

4C 8B D1                  mov r10, rcx
B8 1D 01 00 00            mov eax, 0x11D
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

Notas no documentadas

NtMapUserPhysicalPages enlaza páginas físicas obtenidas vía NtAllocateUserPhysicalPages en la ventana virtual reservada con `VirtualAlloc(MEM_RESERVE | MEM_PHYSICAL)`. Pase NULL como UserPfnArray para desmapear toda la ventana en una sola llamada — propiedad que los motores de base de datos explotan para desalojo rápido de páginas. El re-mapeo es esencialmente una operación solo de TLB en régimen estable: los PFN físicos están fijados, así que no hay IO, no hay ajuste de working-set, no hay soft fault. Ese perfil de latencia (sub-microsegundo en TLB caliente) es exactamente lo que hacía atractivo a AWE para SQL Server de 32 bits cuando PAE era el rodeo del límite de 2 GB.

Uso común por malware

Dos patrones. Primero, **truco de aliasing de página**: un atacante mapea la misma página física en dos direcciones virtuales con protecciones diferentes (p. ej. una ventana RW, otra RX), obteniendo una separación estable escritura-XOR-ejecución sin llamar nunca a NtProtectVirtualMemory — eludiendo a los EDR que hookean cambios de protección. Segundo, **staging de payload resistente al swap**: las páginas se asignan vía AWE una vez y se re-mapean vía este syscall en cada callback de beacon, manteniendo los bytes del payload fuera del archivo de paginación permanentemente. Combinado con un driver vulnerable que expone I/O de memoria física, el mismo syscall puede injertar (tras construir el handle PFN correcto) contenido de página de kernel en una ventana user-mode para primitivas de lectura que sobreviven entre llamadas. El tradecraft requiere SeLockMemoryPrivilege como puerta aguas arriba.

Oportunidades de detección

Las ventanas virtuales MEM_PHYSICAL son visibles en `!vad` como un subtipo distinto y vía `VirtualQueryEx` (Type contiene `MEM_PHYSICAL`). Los EDR que no inspeccionan detalles VAD perderán el mapeo, pero la llamada *aguas arriba* NtAllocateUserPhysicalPages (y el ajuste `SeLockMemoryPrivilege` correspondiente) es un disparador mucho más fiable. Cace procesos que mantengan a la vez una reserva VirtualAlloc MEM_PHYSICAL y llamen a NtMapUserPhysicalPages en bucle — ese es el patrón de cambio de página de una base de datos o un implante con aliasing de payload; si el binario no es sqlservr.exe / exsetup.exe / oracle.exe, merece una mirada más profunda. El ETW Microsoft-Windows-Kernel-Memory no expone directamente los remaps AWE; confíe en los recorridos VAD en el momento del escaneo de memoria.

Ejemplos de syscalls directos

cPage-flip remap loop

// Rotate two batches of physical pages through the same virtual window —
// classic AWE pattern used by SQL Server for buffer-pool extension.
#include <windows.h>

void awe_flip(PVOID window, ULONG_PTR pages, PULONG_PTR pfnA, PULONG_PTR pfnB) {
    for (;;) {
        MapUserPhysicalPages(window, pages, pfnA);   // bring batch A into view
        // ... work on 'window' ...
        MapUserPhysicalPages(window, pages, NULL);   // unmap (NULL pfn array)
        MapUserPhysicalPages(window, pages, pfnB);   // bring batch B into view
        // ... work on 'window' ...
        MapUserPhysicalPages(window, pages, NULL);
    }
}

cW^X aliasing without NtProtectVirtualMemory

// Map the same physical pages twice: one writable window, one executable.
// EDR hooks on NtProtectVirtualMemory never fire because protection never changes.
#include <windows.h>

void* alias_wx(PULONG_PTR pfn, ULONG_PTR pages) {
    SIZE_T size = pages * 4096;
    PVOID wr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE);
    PVOID ex = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_PHYSICAL, PAGE_EXECUTE_READ);
    MapUserPhysicalPages(wr, pages, pfn);
    MapUserPhysicalPages(ex, pages, pfn);
    // Write shellcode via 'wr', execute via 'ex' — same physical memory.
    return ex;
}

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

NtMapUserPhysicalPages PROC
    mov  r10, rcx
    mov  eax, 11Dh
    syscall
    ret
NtMapUserPhysicalPages ENDP

Mapeos MITRE ATT&CK

Last verified: 2026-05-20