NtAllocateVirtualMemoryEx
Reserva o confirma memoria virtual con parámetros extendidos (nodo NUMA preferido, CFG, requisitos de dirección).
Prototipo
NTSTATUS NtAllocateVirtualMemoryEx( HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T RegionSize, ULONG AllocationType, ULONG PageProtection, PMEM_EXTENDED_PARAMETER ExtendedParameters, ULONG ExtendedParameterCount );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle al proceso objetivo. Use NtCurrentProcess() ((HANDLE)-1) para sí mismo. |
| BaseAddress | PVOID* | in/out | Puntero a la dirección base solicitada. NULL deja que el kernel elija. Actualizado al retornar. |
| RegionSize | PSIZE_T | in/out | Puntero al tamaño deseado, redondeado al límite de página al retornar. |
| AllocationType | ULONG | in | Banderas de asignación. MEM_COMMIT | MEM_RESERVE la más común; MEM_RESERVE_PLACEHOLDER y MEM_REPLACE_PLACEHOLDER soportadas. |
| PageProtection | ULONG | in | Constante de protección de memoria. PAGE_TARGETS_INVALID puede combinarse con OR para evadir CFG en las páginas asignadas. |
| ExtendedParameters | PMEM_EXTENDED_PARAMETER | in | Array opcional de entradas MEM_EXTENDED_PARAMETER (nodo NUMA, requisitos de dirección, banderas de atributo). |
| ExtendedParameterCount | ULONG | in | Número de entradas en ExtendedParameters, o 0 si no se usa. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1803 | 0x74 | win10-1803 |
| Win10 1809 | 0x74 | win10-1809 |
| Win10 1903 | 0x74 | win10-1903 |
| Win10 1909 | 0x74 | win10-1909 |
| Win10 2004 | 0x76 | win10-2004 |
| Win10 20H2 | 0x76 | win10-20h2 |
| Win10 21H1 | 0x76 | win10-21h1 |
| Win10 21H2 | 0x76 | win10-21h2 |
| Win10 22H2 | 0x76 | win10-22h2 |
| Win11 21H2 | 0x76 | win11-21h2 |
| Win11 22H2 | 0x76 | win11-22h2 |
| Win11 23H2 | 0x76 | win11-23h2 |
| Win11 24H2 | 0x78 | win11-24h2 |
| Server 2019 | 0x74 | winserver-2019 |
| Server 2022 | 0x76 | winserver-2022 |
| Server 2025 | 0x78 | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 78 00 00 00 mov eax, 0x78 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
Notas no documentadas
NtAllocateVirtualMemoryEx se introdujo en Windows 10 1803 para respaldar las nuevas API VirtualAlloc2 / VirtualAlloc2FromApp. Su SSN ha cambiado tres veces en la ventana soportada — 0x74 en RS4–19H2, 0x76 de 20H1 a 23H2, y 0x78 en 24H2 / Server 2025 — por lo que la resolución dinámica (Hell's Gate / Halo's Gate / Tartarus' Gate) es obligatoria al apuntar a más de un canal. Frente a NtAllocateVirtualMemory añade el array MEM_EXTENDED_PARAMETER y soporta asignaciones placeholder (usadas por Windows para mappings dispersos y estilo memfd).
Uso común por malware
Cada vez más preferido sobre el clásico NtAllocateVirtualMemory por tres motivos. (1) **Superficie menos hookeada**: muchos EDR solo parchean NtAllocateVirtualMemory, dejando la variante Ex sin instrumentar; loaders recientes BumbleBee, IcedID y Latrodectus llaman explícitamente al camino Ex por esta razón. (2) **PAGE_TARGETS_INVALID** marca la región nueva como objetivo de llamada indirecta no válido bajo CFG, y el loader la cambia luego a PAGE_EXECUTE_READ; es el método documentado para evadir CFG cuando el host lo activa. (3) **MEM_EXTENDED_PARAMETER con MemExtendedParameterAddressRequirements** permite al implant pedir una asignación en una dirección alta precisa, útil para suplantar bases de módulos en procesos remotos.
Oportunidades de detección
Asignaciones cross-process por el camino Ex con ExtendedParameterCount distinto de cero son raras fuera de drivers gráficos y brokers AppContainer — alertables. El callback `EtwTiLogAllocExecVm` de ETW Threat Intelligence se dispara tanto en el camino Ex como en la llamada clásica. Sysmon no los distingue de forma nativa; la correlación con NtWriteVirtualMemory / NtCreateThreadEx sigue siendo la señal de comportamiento más barata. Los EDR que solo hookean NtAllocateVirtualMemory lo perderán por completo — verificar cobertura de hooks en ambos nombres durante ejercicios purple-team.
Ejemplos de syscalls directos
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtAllocateVirtualMemoryEx (SSN 0x78 on 24H2/2025)
NtAllocateVirtualMemoryEx PROC
mov r10, rcx ; syscall convention
mov eax, 78h ; SSN — RESOLVE DYNAMICALLY for multi-build targeting
syscall
ret
NtAllocateVirtualMemoryEx ENDPcCFG bypass via PAGE_TARGETS_INVALID
// Allocate RWX page that CFG will not accept as a valid indirect call target.
// Then flip to RX before calling — defeats CFG-only mitigations.
#include <windows.h>
typedef NTSTATUS (NTAPI *pNtAllocateVirtualMemoryEx)(
HANDLE, PVOID*, PSIZE_T, ULONG, ULONG, PMEM_EXTENDED_PARAMETER, ULONG);
PVOID base = NULL;
SIZE_T size = 0x1000;
pNtAllocateVirtualMemoryEx Fn = (pNtAllocateVirtualMemoryEx)
GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtAllocateVirtualMemoryEx");
Fn((HANDLE)-1, &base, &size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE | PAGE_TARGETS_INVALID,
NULL, 0);rustVirtualAlloc2 wrapper
// Cargo: windows-sys = "0.59" (Win32_System_Memory)
use windows_sys::Win32::System::Memory::{
VirtualAlloc2, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE,
};
pub unsafe fn alloc_rwx(size: usize) -> *mut core::ffi::c_void {
VirtualAlloc2(0, core::ptr::null_mut(), size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE,
core::ptr::null_mut(), 0)
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20