> Windows Syscalls
ntoskrnl.exeT1547T1027T1106

NtFlushVirtualMemory

Vacía a disco las páginas modificadas de una vista respaldada por fichero, equivalente a FlushViewOfFile.

Prototipo

NTSTATUS NtFlushVirtualMemory(
  HANDLE           ProcessHandle,
  PVOID           *BaseAddress,
  PSIZE_T          RegionSize,
  PIO_STATUS_BLOCK IoStatus
);

Argumentos

NameTypeDirDescription
ProcessHandleHANDLEinHandle al proceso cuyo mapping debe vaciarse. NtCurrentProcess() para sí mismo.
BaseAddressPVOID*in/outPuntero a la base de la región a vaciar. Al retornar, ajustado a la base realmente vaciada.
RegionSizePSIZE_Tin/outTamaño de la región en bytes. Redondeado al límite de página; tamaño real devuelto en salida.
IoStatusPIO_STATUS_BLOCKoutRecibe el estado de I/O (Status + Information : bytes vaciados).

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070xDCwin10-1507
Win10 16070xDFwin10-1607
Win10 17030xE2win10-1703
Win10 17090xE3win10-1709
Win10 18030xE4win10-1803
Win10 18090xE5win10-1809
Win10 19030xE6win10-1903
Win10 19090xE6win10-1909
Win10 20040xEBwin10-2004
Win10 20H20xEBwin10-20h2
Win10 21H10xEBwin10-21h1
Win10 21H20xECwin10-21h2
Win10 22H20xECwin10-22h2
Win11 21H20xF1win11-21h2
Win11 22H20xF2win11-22h2
Win11 23H20xF2win11-23h2
Win11 24H20xF4win11-24h2
Server 20160xDFwinserver-2016
Server 20190xE5winserver-2019
Server 20220xF0winserver-2022
Server 20250xF4winserver-2025

Módulo del kernel

ntoskrnl.exeNtFlushVirtualMemory

APIs relacionadas

FlushViewOfFileFlushFileBuffersNtCreateSectionNtMapViewOfSectionNtMapViewOfSectionExMapViewOfFile

Stub del syscall

4C 8B D1            mov r10, rcx
B8 F4 00 00 00      mov eax, 0xF4      ; Win11 24H2 SSN
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

Contraparte de `FlushViewOfFile` para secciones respaldadas por un fichero real en disco. El kernel recorre las PTE del rango solicitado, recolecta las páginas dirty y emite I/O de paging hacia el filesystem subyacente — para un fichero memory-mapped es equivalente a un `fsync` solo del subconjunto modificado. Para regiones respaldadas por pagefile o PAGE_NOACCESS la llamada es efectivamente un no-op. El campo `IoStatus.Information` reporta los bytes realmente escritos.

Uso común por malware

Usado en cadenas de persistencia y ransomware que modifican artefactos en disco vía una vista memory-mapped en lugar de `WriteFile`: el atacante mapea un ejecutable, INI, XML de tarea programada o la lista de LSA Notification Packages como `PAGE_READWRITE`, parchea los bytes y llama a `NtFlushVirtualMemory` para forzar la escritura *ahora* en lugar de esperar al lazy writer — importante cuando el siguiente paso (reinicio, reinicio de servicio o exec inmediato) debe ver el cambio en disco. También visto en cadenas de robo de credenciales estilo `MiniDumpWriteDump` que mapean y editan in-place el fichero de dump. Algunas familias de ransomware tocan esta llamada para asegurar que los bytes cifrados llegan al plato antes de borrar shadow copies y forzar un reinicio.

Oportunidades de detección

Sysmon Event 11 (FileCreate) no se dispara en un flush — el fichero ya existe. La telemetría más fiable es el evento ETW `Microsoft-Windows-Kernel-FileIO` `FileIo/OperationEnd` para operaciones `WRITE` cuyos `IrpFlags` indican paging-IO, correlacionado a un proceso que recientemente obtuvo una sección con escritura sobre un fichero sensible (ejecutable en `\System32`, XML de tarea programada, binario referenciado por `ImagePath` en `\Registry\Machine\System\CurrentControlSet\Services\*`). Los EDR que hookean `NtCreateSection` contra rutas de alto valor y luego siguen los `NtFlushVirtualMemory` subsecuentes contra esas vistas atrapan el patrón de patch in-place.

Ejemplos de syscalls directos

cPatch an on-disk binary via mapped view and force flush

// Persistence helper: patch C:\Windows\System32\target.exe in place.
HANDLE hFile = CreateFileW(L"C:\\Windows\\System32\\target.exe",
    GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
    NULL, OPEN_EXISTING, 0, NULL);

HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
PVOID  view = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);

PatchEntryPoint(view);  // overwrite a few bytes

SIZE_T regionSize = /* SizeOfImage rounded up */ 0;
IO_STATUS_BLOCK iosb;
NTSTATUS s = NtFlushVirtualMemory(
    NtCurrentProcess(),
    &view,
    &regionSize,
    &iosb);
// iosb.Information now holds the number of bytes written back.

asmx64 direct stub (Win11 24H2)

; NtFlushVirtualMemory direct stub — SSN 0xF4 on Win11 24H2
NtFlushVirtualMemory PROC
    mov  r10, rcx
    mov  eax, 0F4h
    syscall
    ret
NtFlushVirtualMemory ENDP

rustFlush a mapped region

use ntapi::ntmmapi::NtFlushVirtualMemory;
use winapi::shared::ntdef::HANDLE;
use winapi::shared::ntdef::PVOID;
use winapi::um::winnt::IO_STATUS_BLOCK;
use std::{mem, ptr::null_mut};

unsafe fn flush(view: PVOID, mut size: usize) -> usize {
    let mut base = view;
    let mut iosb: IO_STATUS_BLOCK = mem::zeroed();
    let s = NtFlushVirtualMemory(
        -1isize as HANDLE,
        &mut base,
        &mut size,
        &mut iosb,
    );
    assert!(s >= 0);
    *iosb.Information() as usize
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20