NtMapUserPhysicalPages
Mappt AWE-allokierte physische Seiten in ein zuvor reserviertes virtuelles Adressfenster.
Prototyp
NTSTATUS NtMapUserPhysicalPages( PVOID VirtualAddress, ULONG_PTR NumberOfPages, PULONG_PTR UserPfnArray );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| VirtualAddress | PVOID | in | Basis eines mit MEM_RESERVE | MEM_PHYSICAL reservierten virtuellen Adressfensters. |
| NumberOfPages | ULONG_PTR | in | Anzahl zu mappender Seiten. Darf die Größe des reservierten Fensters nicht überschreiten. |
| UserPfnArray | PULONG_PTR | in | Array opaker Seiten-IDs aus NtAllocateUserPhysicalPages oder NULL zum Unmappen. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x101 | win10-1507 |
| Win10 1607 | 0x106 | win10-1607 |
| Win10 1703 | 0x10A | win10-1703 |
| Win10 1709 | 0x10B | win10-1709 |
| Win10 1803 | 0x10C | win10-1803 |
| Win10 1809 | 0x10D | win10-1809 |
| Win10 1903 | 0x10E | win10-1903 |
| Win10 1909 | 0x10E | win10-1909 |
| Win10 2004 | 0x113 | win10-2004 |
| Win10 20H2 | 0x113 | win10-20h2 |
| Win10 21H1 | 0x113 | win10-21h1 |
| Win10 21H2 | 0x114 | win10-21h2 |
| Win10 22H2 | 0x114 | win10-22h2 |
| Win11 21H2 | 0x11A | win11-21h2 |
| Win11 22H2 | 0x11B | win11-22h2 |
| Win11 23H2 | 0x11B | win11-23h2 |
| Win11 24H2 | 0x11D | win11-24h2 |
| Server 2016 | 0x106 | winserver-2016 |
| Server 2019 | 0x10D | winserver-2019 |
| Server 2022 | 0x119 | winserver-2022 |
| Server 2025 | 0x11D | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
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
Undokumentierte Hinweise
NtMapUserPhysicalPages bindet via NtAllocateUserPhysicalPages erhaltene physische Seiten in das mit `VirtualAlloc(MEM_RESERVE | MEM_PHYSICAL)` reservierte virtuelle Fenster ein. NULL für UserPfnArray übergeben, um das gesamte Fenster in einem Aufruf zu unmappen — eine Eigenschaft, die Datenbank-Engines für schnelle Seiten-Räumung ausnutzen. Das Remapping ist im eingeschwungenen Zustand im Wesentlichen eine reine TLB-Operation: Die physischen PFNs sind gepinnt, also kein I/O, keine Working-Set-Anpassung, kein Soft Fault. Dieses Latenzprofil (Sub-Mikrosekunde bei warmen TLBs) machte AWE damals attraktiv für 32-Bit-SQL-Server, als PAE der Workaround für das 2-GB-Limit war.
Häufige Malware-Nutzung
Zwei Muster. Erstens, **Page-Aliasing-Trick**: Ein Angreifer mappt dieselbe physische Seite in zwei virtuelle Adressen mit unterschiedlichen Schutzrechten (z. B. ein Fenster RW, ein anderes RX) und erhält eine stabile Write-XOR-Execute-Trennung, ohne je NtProtectVirtualMemory aufzurufen — und umgeht damit EDRs, die Schutzänderungen hooken. Zweitens, **swap-resistentes Payload-Staging**: Seiten werden einmal AWE-allokiert und bei jedem Beacon-Callback über diesen Syscall remappt, sodass die Payload-Bytes dauerhaft aus der Pagefile herausbleiben. Kombiniert mit einem verwundbaren Treiber, der physisches Speicher-I/O exponiert, kann derselbe Syscall (nach Bau des passenden PFN-Handles) Kernel-Seiteninhalte in ein User-Mode-Fenster splicen — für aufrufübergreifend persistente Read-Primitives. Tradecraft erfordert SeLockMemoryPrivilege als vorgelagerte Hürde.
Erkennungsmöglichkeiten
MEM_PHYSICAL-virtuelle Fenster sind in `!vad` als eigener Subtyp und via `VirtualQueryEx` sichtbar (Type enthält `MEM_PHYSICAL`). EDRs ohne VAD-Detail-Introspektion verpassen das Mapping, aber der *vorgelagerte* NtAllocateUserPhysicalPages-Aufruf (und die zugehörige `SeLockMemoryPrivilege`-Anpassung) ist ein deutlich verlässlicherer Trigger. Jagd auf Prozesse, die gleichzeitig eine MEM_PHYSICAL-VirtualAlloc-Reservierung halten und NtMapUserPhysicalPages in einer Schleife aufrufen — das ist das Page-Flipping-Muster einer Datenbank oder eines Payload-Aliasing-Implants; ist die Binary nicht sqlservr.exe / exsetup.exe / oracle.exe, lohnt ein genauerer Blick. ETW Microsoft-Windows-Kernel-Memory exponiert AWE-Remaps nicht direkt; verlassen Sie sich auf VAD-Walks zur Memory-Scan-Zeit.
Direkte Syscall-Beispiele
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 ENDPMITRE ATT&CK-Mappings
Last verified: 2026-05-20