NtFreeUserPhysicalPages
Gibt zuvor über NtAllocateUserPhysicalPages allokierte physische Seiten frei und führt sie an den Systemseiten-Pool zurück.
Prototyp
NTSTATUS NtFreeUserPhysicalPages( HANDLE ProcessHandle, PULONG_PTR NumberOfPages, PULONG_PTR UserPfnArray );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle auf den Prozess, dem das AWE-PFN-Array gehört. Üblicherweise NtCurrentProcess(). |
| NumberOfPages | PULONG_PTR | in/out | Eingabe: zu befreiende Seitenzahl. Ausgabe: tatsächlich freigegebene Anzahl. |
| UserPfnArray | PULONG_PTR | in | Array opaker PFN-Identifier, von NtAllocateUserPhysicalPages erhalten. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0xDE | win10-1507 |
| Win10 1607 | 0xE1 | win10-1607 |
| Win10 1703 | 0xE4 | win10-1703 |
| Win10 1709 | 0xE5 | win10-1709 |
| Win10 1803 | 0xE6 | win10-1803 |
| Win10 1809 | 0xE7 | win10-1809 |
| Win10 1903 | 0xE8 | win10-1903 |
| Win10 1909 | 0xE8 | win10-1909 |
| Win10 2004 | 0xED | win10-2004 |
| Win10 20H2 | 0xED | win10-20h2 |
| Win10 21H1 | 0xED | win10-21h1 |
| Win10 21H2 | 0xEE | win10-21h2 |
| Win10 22H2 | 0xEE | win10-22h2 |
| Win11 21H2 | 0xF3 | win11-21h2 |
| Win11 22H2 | 0xF4 | win11-22h2 |
| Win11 23H2 | 0xF4 | win11-23h2 |
| Win11 24H2 | 0xF6 | win11-24h2 |
| Server 2016 | 0xE1 | winserver-2016 |
| Server 2019 | 0xE7 | winserver-2019 |
| Server 2022 | 0xF2 | winserver-2022 |
| Server 2025 | 0xF6 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
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
Undokumentierte Hinweise
Das Cleanup-Pendant zu `NtAllocateUserPhysicalPages`. Läuft das PFN-Array durch, dekrementiert den Referenzzähler jeder Seite in der System-PFN-Datenbank und führt die Seiten an Standby-/Free-List zurück. Seiten, die noch über `NtMapUserPhysicalPages` gemappt sind, werden zuvor aus dem Adressraum-Fenster des Aufrufers entkoppelt. Wie der Allocator-Zwilling verlangt der Aufruf, dass der Prozess `SeLockMemoryPrivilege` aktuell besitzt oder zum Zeitpunkt der Allokation besessen hat — der Kernel speichert den Ursprungs-Token bei der Allokation und nutzt ihn für Eigentumsprüfungen. `NtFreeUserPhysicalPages` auf PFN-Werten, die nicht aus demselben Allocator stammen, gibt `STATUS_INVALID_PARAMETER_3` zurück, ohne Systemzustand zu berühren.
Häufige Malware-Nutzung
Minimaler direkter offensiver Wert — er ist rein der Destruktor eines ohnehin seltenen Allokationspfads. Auftauchend dort, wo es um **Anti-Forensik-Cleanup** geht: Implants, die Shellcode in AWE-gesicherten nicht-pageable Seiten staged haben (um Memory-Pressure-Swap-Captures zu überleben), rufen `NtFreeUserPhysicalPages` direkt vor dem Beenden des Implants, damit eine Post-Incident-`vmcore`- oder Hibernation-File-Analyse keine residualen nicht-pageable Regionen mit Bezug zum toten Prozess findet. Auch in **Kernel-R/W-Primitiv-Teardown**-Ketten zu sehen, in denen der Angreifer AWE-Seiten allokiert, um Kernel-Speicher über einen verwundbaren Treiber zu aliasen, und sie dann freigibt, um die einzige persistente forensische Spur zu beseitigen. Commodity-Malware nutzt es praktisch nie.
Erkennungsmöglichkeiten
Spiegelbild des Allocator-Signals — gepaarte Aufrufe von `NtAllocateUserPhysicalPages` und `NtFreeUserPhysicalPages` aus demselben Nicht-DB-Server-Prozess sind das hochrelevante Indiz, besonders bei kurzer Lebensdauer (allokieren → mappen → ausführen → freigeben innerhalb derselben Sekunde). Sysmon Event ID 1 für den Eltern-Prozess kombiniert mit dem Kernel-ETW-Event `Microsoft-Windows-Kernel-Memory` 14 (Familie `PfnPageRelease`) erlaubt die Lifecycle-Rekonstruktion. Das `SeLockMemoryPrivilege`-Audit (Event 4673) feuert normalerweise nur auf dem Allokationspfad; sieht man einen freigebenden Prozess, ohne dass das Audit-Log einen entsprechenden Grant zeigt, war das Privileg im Eltern-Token bereits aktiviert — Herkunft prüfen.
Direkte Syscall-Beispiele
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 ENDPMITRE ATT&CK-Mappings
Last verified: 2026-05-20