NtAllocateVirtualMemory
Réserve, valide ou les deux une région de mémoire virtuelle dans un processus cible.
Prototype
NTSTATUS NtAllocateVirtualMemory( HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle vers le processus cible. Utilisez NtCurrentProcess() ((HANDLE)-1) pour soi-même. |
| BaseAddress | PVOID* | in/out | Pointeur vers l'adresse de base demandée. NULL laisse le noyau choisir. Mis à jour au retour. |
| ZeroBits | ULONG_PTR | in | Nombre de bits de poids fort à zéro dans BaseAddress. Typiquement 0. |
| RegionSize | PSIZE_T | in/out | Pointeur vers la taille souhaitée, arrondie à la page supérieure au retour. |
| AllocationType | ULONG | in | Drapeaux d'allocation. MEM_COMMIT | MEM_RESERVE est la combinaison la plus courante. |
| Protect | ULONG | in | Constante de protection mémoire, ex. PAGE_READWRITE, PAGE_EXECUTE_READWRITE. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1909 | 0x18 | win10-1909 |
| Win10 2004 | 0x18 | win10-2004 |
| Win10 20H2 | 0x18 | win10-20h2 |
| Win10 21H1 | 0x18 | win10-21h1 |
| Win10 21H2 | 0x18 | win10-21h2 |
| Win10 22H2 | 0x18 | win10-22h2 |
| Win11 21H2 | 0x18 | win11-21h2 |
| Win11 22H2 | 0x18 | win11-22h2 |
| Win11 23H2 | 0x18 | win11-23h2 |
| Win11 24H2 | 0x18 | win11-24h2 |
| Server 2019 | 0x18 | winserver-2019 |
| Server 2022 | 0x18 | winserver-2022 |
| Server 2025 | 0x18 | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 18 00 00 00 mov eax, 0x18 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 numéro de syscall de NtAllocateVirtualMemory est resté remarquablement stable de Windows 10 1909 jusqu'à Windows 11 24H2 — `0x18`. Ce n'est *pas* le cas de nombreux syscalls adjacents (ex. NtCreateThreadEx), ce qui explique pourquoi la résolution dynamique via Hell's Gate ou Halo's Gate est préférée aux numéros codés en dur lorsqu'on cible plusieurs builds. La fonction passe par KiSystemServiceCopyEnd → MmAllocateVirtualMemory dans ntoskrnl.exe.
Usage courant par les malwares
Fondamental pour pratiquement tout loader de shellcode : allouer de la mémoire RW ou RWX dans le processus courant ou distant, copier le payload, puis changer la protection avec NtProtectVirtualMemory. Utilisé par le spawn de beacon Cobalt Strike, les implants Sliver, l'injection classique, et la plupart des droppers du commerce. Combiné à NtWriteVirtualMemory + NtCreateThreadEx, il forme la chaîne canonique équivalente à CreateRemoteThread en syscalls directs.
Opportunités de détection
Pris isolément, NtAllocateVirtualMemory est *extrêmement* courant en logiciel légitime et n'est pas un signal exploitable. Ce qui compte, c'est *comment* et *où* il est appelé : allocations RWX, allocations dans des processus distants, séquences courtes RW→RX→exécution. Les EDR hookent NtAllocateVirtualMemory dans ntdll.dll ; les syscalls directs contournent ce hook mais laissent des artefacts visibles côté noyau (entrées VAD, événements ETW Threat Intelligence, callbacks PsSetCreateProcessNotifyRoutineEx pour la création de thread distant). Sysmon Event ID 8 (CreateRemoteThread) et Event ID 10 (ProcessAccess avec VM_OPERATION/VM_WRITE) sont les télémétries blue-team les plus utiles — elles se déclenchent sur les *conséquences* de l'allocation, pas l'allocation elle-même.
Exemples de syscalls directs
asmx64 direct stub
; Direct syscall stub for NtAllocateVirtualMemory (SSN 0x18, Win10 1909+)
NtAllocateVirtualMemory PROC
mov r10, rcx ; syscall convention
mov eax, 18h ; SSN
syscall
ret
NtAllocateVirtualMemory ENDPcHell's Gate dynamic lookup
// Resolve SSN dynamically from ntdll export at runtime — survives KB updates.
DWORD GetSyscallNumber(PVOID pNtFunction) {
BYTE* p = (BYTE*)pNtFunction;
if (p[0] == 0x4C && p[1] == 0x8B && p[2] == 0xD1 && p[3] == 0xB8) {
return *(DWORD*)(p + 4);
}
return 0;
}
// usage
HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
DWORD ssn = GetSyscallNumber(GetProcAddress(hNtdll, "NtAllocateVirtualMemory"));rustwindows-sys + naked asm
// Cargo: windows-sys = "0.59" (Win32_Foundation, Win32_System_Memory)
use std::arch::asm;
#[unsafe(naked)]
unsafe extern "system" fn nt_alloc_virtual_memory_stub() {
asm!(
"mov r10, rcx",
"mov eax, 0x18",
"syscall",
"ret",
options(noreturn),
);
}Mappings MITRE ATT&CK
Last verified: 2026-05-20