> Windows Syscalls
ntoskrnl.exeT1106T1070

NtFreeUserPhysicalPages

Libère des pages physiques précédemment allouées via NtAllocateUserPhysicalPages, en les rendant au pool système.

Prototype

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

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle vers le processus propriétaire du tableau PFN AWE. Généralement NtCurrentProcess().
NumberOfPagesPULONG_PTRin/outEn entrée : nombre de pages à libérer. En sortie : nombre effectivement libéré.
UserPfnArrayPULONG_PTRinTableau d'identifiants PFN opaques obtenus depuis NtAllocateUserPhysicalPages.

IDs de syscalls par version de Windows

Version 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

Module noyau

ntoskrnl.exeNtFreeUserPhysicalPages

APIs liées

FreeUserPhysicalPagesAllocateUserPhysicalPagesMapUserPhysicalPagesNtAllocateUserPhysicalPagesNtMapUserPhysicalPages

Stub du 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

Notes non documentées

Le pendant de nettoyage de `NtAllocateUserPhysicalPages`. Parcourt le tableau PFN, décrémente le compteur de référence de chaque page dans la base PFN système, et rend les pages aux listes standby / free. Les pages encore mappées via `NtMapUserPhysicalPages` sont d'abord démappées de la fenêtre d'espace d'adressage de l'appelant. Comme son jumeau allocator, l'appel requiert que le processus détienne actuellement `SeLockMemoryPrivilege` ou l'ait détenu au moment de l'allocation — le noyau enregistre le token d'origine au moment de l'allocation et s'en sert pour les vérifications de propriété. Appeler `NtFreeUserPhysicalPages` sur des valeurs PFN ne provenant pas du même allocator renvoie `STATUS_INVALID_PARAMETER_3` sans toucher à l'état système.

Usage courant par les malwares

Valeur offensive directe minimale — c'est purement le destructeur d'un chemin d'allocation déjà rare. Là où il apparaît, c'est dans le **nettoyage anti-forensique** : les implants qui ont mis en place du shellcode dans des pages AWE non-paginables (pour survivre aux captures de swap sous pression mémoire) appellent `NtFreeUserPhysicalPages` juste avant la sortie de l'implant, pour qu'une analyse post-incident `vmcore` ou de fichier d'hibernation ne voie aucune région non-paginable résiduelle liée au processus mort. Apparaît aussi dans les chaînes de **démontage de primitive R/W noyau** où l'attaquant alloue des pages AWE pour aliaser de la mémoire noyau via un driver vulnérable puis les libère pour effacer la seule trace forensique persistante. Le malware commodity n'y touche pratiquement jamais.

Opportunités de détection

Miroir du signal de l'allocator — les appels appariés de `NtAllocateUserPhysicalPages` et `NtFreeUserPhysicalPages` depuis un même processus non serveur-de-base-de-données sont l'indicateur haute-fidélité, surtout quand la durée de vie est courte (allouer → mapper → exécuter → libérer dans la même seconde). Sysmon Event ID 1 pour le processus parent combiné à l'évènement ETW noyau `Microsoft-Windows-Kernel-Memory` 14 (famille `PfnPageRelease`) permet de reconstruire le cycle de vie. L'audit `SeLockMemoryPrivilege` (Event 4673) ne se déclenche habituellement que sur le chemin d'allocation ; si vous voyez un processus libérer alors que le journal d'audit n'a pas d'octroi correspondant, le privilège était déjà activé dans le token parent — investiguez d'où il vient.

Exemples de syscalls directs

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

Mappings MITRE ATT&CK

Last verified: 2026-05-20