NtAllocateVirtualMemory
Reserviert, committet oder beides eine virtuelle Speicherregion in einem Zielprozess.
Prototyp
NTSTATUS NtAllocateVirtualMemory( HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle auf den Zielprozess. NtCurrentProcess() ((HANDLE)-1) für den eigenen Prozess. |
| BaseAddress | PVOID* | in/out | Zeiger auf die gewünschte Basisadresse. NULL lässt den Kernel wählen. Wird beim Rückkehren aktualisiert. |
| ZeroBits | ULONG_PTR | in | Anzahl der Null-Bits in den höchstwertigen Bits von BaseAddress. Üblicherweise 0. |
| RegionSize | PSIZE_T | in/out | Zeiger auf die gewünschte Größe, beim Rückkehren auf Seitengrenze aufgerundet. |
| AllocationType | ULONG | in | Allocation-Flags. MEM_COMMIT | MEM_RESERVE ist die häufigste Kombination. |
| Protect | ULONG | in | Speicherschutz-Konstante, z. B. PAGE_READWRITE, PAGE_EXECUTE_READWRITE. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | 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 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
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
Undokumentierte Hinweise
Die Syscall-Nummer von NtAllocateVirtualMemory ist von Windows 10 1909 bis Windows 11 24H2 bemerkenswert stabil — `0x18`. Bei vielen benachbarten Syscalls (z. B. NtCreateThreadEx) ist das *nicht* der Fall, weshalb dynamische Auflösung über Hell's Gate oder Halo's Gate gegenüber hartkodierten Nummern bevorzugt wird, wenn mehrere Builds anvisiert werden. Die Funktion dispatcht über KiSystemServiceCopyEnd → MmAllocateVirtualMemory innerhalb von ntoskrnl.exe.
Häufige Malware-Nutzung
Grundbaustein nahezu jedes Shellcode-Loaders: RW- oder RWX-Speicher im aktuellen oder Remote-Prozess allokieren, Payload kopieren, dann Schutz mit NtProtectVirtualMemory ändern. Wird verwendet von Cobalt-Strike-Beacon-Spawn, Sliver-Implants, klassischer Injection und den meisten Standard-Droppern. Zusammen mit NtWriteVirtualMemory + NtCreateThreadEx bildet es die kanonische CreateRemoteThread-Entsprechung über direkte Syscalls.
Erkennungsmöglichkeiten
Für sich allein ist NtAllocateVirtualMemory in legitimer Software *äußerst* häufig und kein nützliches Signal. Entscheidend ist *wie* und *wo* der Aufruf erfolgt: RWX-Allokationen, Allokationen in Remote-Prozessen sowie kurze RW→RX→Ausführen-Sequenzen. EDRs hooken NtAllocateVirtualMemory in ntdll.dll; direkte Syscalls umgehen diesen Hook, hinterlassen aber kernelseitig sichtbare Artefakte (VAD-Einträge, ETW-Threat-Intelligence-Events, PsSetCreateProcessNotifyRoutineEx-Callbacks bei Remote-Thread-Erzeugung). Sysmon Event ID 8 (CreateRemoteThread) und Event ID 10 (ProcessAccess mit VM_OPERATION/VM_WRITE) sind die wertvollste Blue-Team-Telemetrie — sie feuern auf die *Folgen* der Allokation, nicht die Allokation selbst.
Direkte Syscall-Beispiele
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),
);
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20