NtMapUserPhysicalPages
Mappe des pages physiques allouées via AWE dans une fenêtre d'adresse virtuelle préalablement réservée.
Prototype
NTSTATUS NtMapUserPhysicalPages( PVOID VirtualAddress, ULONG_PTR NumberOfPages, PULONG_PTR UserPfnArray );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| VirtualAddress | PVOID | in | Base d'une fenêtre d'adresse virtuelle réservée avec MEM_RESERVE | MEM_PHYSICAL. |
| NumberOfPages | ULONG_PTR | in | Nombre de pages à mapper. Ne doit pas dépasser la taille de la fenêtre réservée. |
| UserPfnArray | PULONG_PTR | in | Tableau d'identifiants de page opaques issus de NtAllocateUserPhysicalPages, ou NULL pour démapper. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | 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 |
Module noyau
APIs liées
Stub du 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
Notes non documentées
NtMapUserPhysicalPages lie les pages physiques obtenues via NtAllocateUserPhysicalPages dans la fenêtre virtuelle réservée par `VirtualAlloc(MEM_RESERVE | MEM_PHYSICAL)`. Passez NULL pour UserPfnArray afin de démapper toute la fenêtre en un appel — propriété exploitée par les moteurs de base de données pour une éviction de page rapide. Le remappage est essentiellement une opération purement TLB en régime stable : les PFN physiques sont épinglés, donc pas d'IO, pas d'ajustement de working-set, pas de soft fault. Ce profil de latence (sous-microseconde sur TLB chaud) est exactement ce qui rendait AWE attractif pour SQL Server 32 bits à l'époque où PAE était un contournement de la limite 2 Go.
Usage courant par les malwares
Deux schémas. Premièrement, **astuce d'aliasing de page** : un attaquant mappe la même page physique dans deux adresses virtuelles avec protections différentes (par ex. une fenêtre RW, une autre RX), obtenant une séparation stable écriture-XOR-exécution sans jamais appeler NtProtectVirtualMemory — contournant les EDR qui hookent les changements de protection. Deuxièmement, **mise en scène de payload résistante au swap** : les pages sont allouées AWE une fois et remappées via ce syscall à chaque rappel de beacon, gardant les octets du payload hors du fichier d'échange en permanence. Combiné à un driver vulnérable exposant des I/O mémoire physique, le même syscall peut greffer (après construction du bon handle PFN) le contenu d'une page noyau dans une fenêtre user-mode pour des primitives de lecture qui survivent entre appels. Le tradecraft requiert SeLockMemoryPrivilege en amont.
Opportunités de détection
Les fenêtres virtuelles MEM_PHYSICAL sont visibles dans `!vad` comme sous-type distinct et via `VirtualQueryEx` (Type contient `MEM_PHYSICAL`). Les EDR qui n'introspectent pas les détails VAD rateront le mapping, mais l'appel *amont* NtAllocateUserPhysicalPages (et l'ajustement `SeLockMemoryPrivilege` correspondant) est un déclencheur bien plus fiable. Chassez les processus qui détiennent à la fois une réservation VirtualAlloc MEM_PHYSICAL et appellent NtMapUserPhysicalPages en boucle — c'est le pattern de retournement de page d'une base de données ou d'un implant à aliasing de payload ; si le binaire n'est pas sqlservr.exe / exsetup.exe / oracle.exe, il mérite un examen plus profond. L'ETW Microsoft-Windows-Kernel-Memory n'expose pas directement les remaps AWE ; comptez sur les parcours VAD au moment du scan mémoire.
Exemples de syscalls directs
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 ENDPMappings MITRE ATT&CK
Last verified: 2026-05-20