> Windows Syscalls
ntoskrnl.exeT1106T1070

NtFreeUserPhysicalPages

Libera páginas físicas previamente asignadas vía NtAllocateUserPhysicalPages, devolviéndolas al pool del sistema.

Prototipo

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

Argumentos

NameTypeDirDescription
ProcessHandleHANDLEinHandle al proceso que posee el arreglo PFN AWE. Habitualmente NtCurrentProcess().
NumberOfPagesPULONG_PTRin/outEn entrada: número de páginas a liberar. En salida: número realmente liberado.
UserPfnArrayPULONG_PTRinArreglo de identificadores PFN opacos obtenidos de NtAllocateUserPhysicalPages.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070xDEwin10-1507
Win10 16070xE1win10-1607
Win10 17030xE4win10-1703
Win10 17090xE5win10-1709
Win10 18030xE6win10-1803
Win10 18090xE7win10-1809
Win10 19030xE8win10-1903
Win10 19090xE8win10-1909
Win10 20040xEDwin10-2004
Win10 20H20xEDwin10-20h2
Win10 21H10xEDwin10-21h1
Win10 21H20xEEwin10-21h2
Win10 22H20xEEwin10-22h2
Win11 21H20xF3win11-21h2
Win11 22H20xF4win11-22h2
Win11 23H20xF4win11-23h2
Win11 24H20xF6win11-24h2
Server 20160xE1winserver-2016
Server 20190xE7winserver-2019
Server 20220xF2winserver-2022
Server 20250xF6winserver-2025

Módulo del kernel

ntoskrnl.exeNtFreeUserPhysicalPages

APIs relacionadas

FreeUserPhysicalPagesAllocateUserPhysicalPagesMapUserPhysicalPagesNtAllocateUserPhysicalPagesNtMapUserPhysicalPages

Stub del syscall

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

La contraparte de limpieza de `NtAllocateUserPhysicalPages`. Recorre el arreglo PFN, decrementa el contador de referencia de cada página en la base PFN del sistema y devuelve las páginas a las listas standby / free. Las páginas todavía mapeadas vía `NtMapUserPhysicalPages` se desmapean primero de la ventana de espacio de direcciones del llamante. Como su gemelo allocator, la llamada requiere que el proceso o bien posea actualmente `SeLockMemoryPrivilege` o lo poseyera al momento de la asignación — el kernel registra el token de origen en el momento de la asignación y lo usa para verificaciones de propiedad. Llamar `NtFreeUserPhysicalPages` sobre valores PFN que no provienen del mismo allocator devuelve `STATUS_INVALID_PARAMETER_3` sin tocar el estado del sistema.

Uso común por malware

Valor ofensivo directo mínimo — es puramente el destructor de un camino de asignación ya raro. Donde aparece es en la **limpieza anti-forense**: implantes que stagearon shellcode en páginas AWE no-paginables (para sobrevivir capturas de swap por presión de memoria) llaman `NtFreeUserPhysicalPages` justo antes de la salida del implante, para que un análisis post-incidente de `vmcore` o de archivo de hibernación no vea ninguna región no-paginable residual atada al proceso muerto. También aparece en cadenas de **desmontaje de primitiva R/W de kernel** donde el atacante asigna páginas AWE para aliasar memoria del kernel vía un driver vulnerable y luego las libera para borrar el único rastro forense persistente. El malware commodity prácticamente nunca lo toca.

Oportunidades de detección

Espejo de la señal del allocator — llamadas pareadas de `NtAllocateUserPhysicalPages` y `NtFreeUserPhysicalPages` desde un mismo proceso no servidor-de-base-de-datos son el indicador alta-fidelidad, especialmente cuando el tiempo de vida es corto (asignar → mapear → ejecutar → liberar en el mismo segundo). Sysmon Event ID 1 para el proceso padre combinado con el evento ETW de kernel `Microsoft-Windows-Kernel-Memory` 14 (familia `PfnPageRelease`) permite reconstruir el ciclo de vida. La auditoría de `SeLockMemoryPrivilege` (Event 4673) suele dispararse solo en el camino de asignación; si ve un proceso liberando cuando el log de auditoría no tiene una concesión correspondiente, el privilegio ya estaba habilitado en el token padre — investigue de dónde vino.

Ejemplos de syscalls directos

cFree AWE pages and the windowing region

// Pair with the NtAllocateUserPhysicalPages example: tear down the AWE working
// set so that the shellcode-bearing physical pages are returned to the free list
// before the implant exits.
#include <windows.h>

void awe_free(ULONG_PTR* pfn, SIZE_T pages, PVOID windowBase) {
    // First unmap from the window so no live VAD references the PFNs.
    MapUserPhysicalPages(windowBase, pages, NULL);
    VirtualFree(windowBase, 0, MEM_RELEASE);

    ULONG_PTR n = pages;
    FreeUserPhysicalPages(GetCurrentProcess(), &n, pfn);
    // Wrapper resolves to NtFreeUserPhysicalPages internally.
}

asmx64 direct stub (Win11 24H2 / Server 2025, SSN 0xF6)

NtFreeUserPhysicalPages PROC
    mov  r10, rcx
    mov  eax, 0F6h
    syscall
    ret
NtFreeUserPhysicalPages ENDP

Mapeos MITRE ATT&CK

Last verified: 2026-05-20