> Windows Syscalls
ntoskrnl.exeT1574T1055T1106

NtSetInformationVirtualMemory

Aplica una clase de información a una lista de rangos de memoria virtual: prefetch, prioridad de página u opt-in CFG.

Prototipo

NTSTATUS NtSetInformationVirtualMemory(
  HANDLE                          ProcessHandle,
  VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass,
  ULONG_PTR                       NumberOfEntries,
  PMEMORY_RANGE_ENTRY             VirtualAddresses,
  PVOID                           VmInformation,
  ULONG                           VmInformationLength
);

Argumentos

NameTypeDirDescription
ProcessHandleHANDLEinHandle del proceso objetivo. NtCurrentProcess() ((HANDLE)-1) para sí mismo.
VmInformationClassVIRTUAL_MEMORY_INFORMATION_CLASSinOperación: VmPrefetchInformation, VmPagePriorityInformation, VmCfgCallTargetInformation, VmPageDirtyStateInformation, VmImageHotPatchInformation.
NumberOfEntriesULONG_PTRinCantidad de entradas en VirtualAddresses. Varias clases (notablemente CfgCallTarget) exigen exactamente 1.
VirtualAddressesPMEMORY_RANGE_ENTRYinArreglo de rangos {VirtualAddress, NumberOfBytes} sobre los que actuar.
VmInformationPVOIDinCarga específica de la clase: banderas ULONG para prefetch, MEMORY_PRIORITY_INFORMATION para prioridad, CFG_CALL_TARGET_INFO[] para CFG.
VmInformationLengthULONGinTamaño en bytes de la carga útil VmInformation.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070x182win10-1507
Win10 16070x18Bwin10-1607
Win10 17030x191win10-1703
Win10 17090x194win10-1709
Win10 18030x196win10-1803
Win10 18090x197win10-1809
Win10 19030x198win10-1903
Win10 19090x198win10-1909
Win10 20040x19Ewin10-2004
Win10 20H20x19Ewin10-20h2
Win10 21H10x19Ewin10-21h1
Win10 21H20x1A0win10-21h2
Win10 22H20x1A0win10-22h2
Win11 21H20x1A9win11-21h2
Win11 22H20x1ADwin11-22h2
Win11 23H20x1ADwin11-23h2
Win11 24H20x1B0win11-24h2
Server 20160x18Bwinserver-2016
Server 20190x197winserver-2019
Server 20220x1A6winserver-2022
Server 20250x1B0winserver-2025

Módulo del kernel

ntoskrnl.exeNtSetInformationVirtualMemory

APIs relacionadas

PrefetchVirtualMemoryOfferVirtualMemorySetProcessValidCallTargetsVirtualAllocFromAppNtAllocateVirtualMemoryExNtProtectVirtualMemory

Stub del syscall

4C 8B D1            mov r10, rcx
B8 B0 01 00 00      mov eax, 0x1B0
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

Introducido como parte de la API de aviso VM multi-rango de Windows 10 y extendido sustancialmente con cada release. Las clases de información operativamente más interesantes son: **VmPrefetchInformation** — calienta un vector de rangos de direcciones antes del acceso (la columna vertebral del kernel de PrefetchVirtualMemory/OfferVirtualMemory); **VmPagePriorityInformation** — establece hints de prioridad de paginación; **VmCfgCallTargetInformation** — marca direcciones específicas dentro de un módulo con CFG como destinos válidos de llamada indirecta, el mecanismo en kernel detrás de SetProcessValidCallTargets y la única vía sancionada para que un JIT publique código recién emitido en un proceso protegido por CFG; **VmImageHotPatchInformation** — usado por HotPatch en Server 2022+ / 24H2.

Uso común por malware

Dos historias de abuso distintas. (1) **Investigación de bypass CFG**: VmCfgCallTargetInformation es la puerta legítima para decirle a CFG que una dirección arbitraria es ahora un destino válido. Si un atacante que ya logró read/write arbitrario en un proceso protegido por CFG puede llamarlo — o falsificar la actualización del bitmap en lado del kernel — puede rehabilitar gadgets arbitrarios como destinos legítimos de llamada indirecta. Varios writeups públicos de bypass CFG (Yarden Shafir, notas antiguas de j00ru) cubren la superficie. El endurecimiento moderno empareja CFG con Xtended Flow Guard (XFG) y Arbitrary Code Guard precisamente para neutralizar esto. (2) **Cobertura de inyección JIT**: los navegadores y .NET legítimos usan VmCfgCallTargetInformation constantemente, así que un loader de payload que imita la misma forma de llamada (allocate ejecutable, escribir código, llamar NtSetInformationVirtualMemory con VmCfgCallTargetInformation) se mezcla con la telemetría de referencia dentro de un proceso clase navegador. Menos común pero documentado.

Oportunidades de detección

Los EDR deberían marcar llamadas VmCfgCallTargetInformation desde procesos sin JIT (cualquier cosa fuera de chrome.exe, msedge.exe, firefox.exe, dotnet.exe / apps hospedadas en coreclr, javaw.exe, hosts con JScript9.dll). ETW Microsoft-Windows-Threat-Intelligence emite eventos de cambio de estado de memoria al emparejarse con transiciones de páginas ejecutables. Sysmon no cubre directamente esta syscall; depender del callback de syscall del sensor EDR (Kernel-Microsoft-Antimalware-AMFilter en sistemas con AMSI instrumentado). La superficie Win32 (SetProcessValidCallTargets, PrefetchVirtualMemory) está hookeada por todos los EDR principales.

Ejemplos de syscalls directos

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtSetInformationVirtualMemory (SSN 0x1B0, Win11 24H2)
NtSetInformationVirtualMemory PROC
    mov  r10, rcx
    mov  eax, 1B0h
    syscall
    ret
NtSetInformationVirtualMemory ENDP

cJIT opt-in for CFG (VmCfgCallTargetInformation)

// JIT just emitted callable code at `jit_buf` (size = jit_len). Tell CFG it's legal
// to indirect-call into the new entrypoints. Mirrors what V8 / CoreCLR do.
typedef struct _CFG_CALL_TARGET_INFO {
    ULONG_PTR Offset;
    ULONG_PTR Flags;
} CFG_CALL_TARGET_INFO;

typedef struct _MEMORY_RANGE_ENTRY {
    PVOID    VirtualAddress;
    SIZE_T   NumberOfBytes;
} MEMORY_RANGE_ENTRY;

#define VmCfgCallTargetInformation 2
#define CFG_CALL_TARGET_VALID      0x01

MEMORY_RANGE_ENTRY range = { jit_buf, jit_len };
CFG_CALL_TARGET_INFO targets[] = {
    { (ULONG_PTR)entry0 - (ULONG_PTR)jit_buf, CFG_CALL_TARGET_VALID },
    { (ULONG_PTR)entry1 - (ULONG_PTR)jit_buf, CFG_CALL_TARGET_VALID },
};

NTSTATUS s = NtSetInformationVirtualMemory(
    NtCurrentProcess(),
    VmCfgCallTargetInformation,
    1,
    &range,
    targets,
    sizeof(targets));

rustPrefetchVirtualMemory equivalent via VmPrefetchInformation

// Warm a list of memory ranges before the latency-sensitive work touches them.
// VmPrefetchInformation = 0.
#[repr(C)]
struct MemoryRangeEntry { addr: *mut u8, bytes: usize }

extern "system" {
    fn NtSetInformationVirtualMemory(
        process: isize,
        class: u32,
        n: usize,
        ranges: *const MemoryRangeEntry,
        info: *const u32,
        info_len: u32,
    ) -> i32;
}

unsafe fn prefetch(ranges: &[MemoryRangeEntry]) -> i32 {
    let flags: u32 = 0;
    NtSetInformationVirtualMemory(
        -1, 0, ranges.len(), ranges.as_ptr(),
        &flags, std::mem::size_of::<u32>() as u32)
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20