> Windows Syscalls
ntoskrnl.exeT1547T1027T1106

NtFlushVirtualMemory

Vide sur disque les pages modifiées d'une vue adossée à un fichier, équivalent à FlushViewOfFile.

Prototype

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

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle vers le processus dont le mapping doit être flushé. NtCurrentProcess() pour soi-même.
BaseAddressPVOID*in/outPointeur vers la base de la région à flusher. Au retour, défini sur la base réellement flushée.
RegionSizePSIZE_Tin/outTaille de la région en octets. Arrondie à la page supérieure ; taille réelle retournée en sortie.
IoStatusPIO_STATUS_BLOCKoutReçoit le statut d'I/O (Status + Information : octets flushés).

IDs de syscalls par version de Windows

Version 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

Module noyau

ntoskrnl.exeNtFlushVirtualMemory

APIs liées

FlushViewOfFileFlushFileBuffersNtCreateSectionNtMapViewOfSectionNtMapViewOfSectionExMapViewOfFile

Stub du 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

Notes non documentées

Pendant de `FlushViewOfFile` pour les sections adossées à un vrai fichier disque. Le noyau parcourt les PTE sur la plage demandée, collecte les pages dirty et émet des I/O de paging vers le système de fichiers sous-jacent — pour un fichier memory-mapped, c'est l'équivalent d'un `fsync` du seul sous-ensemble modifié. Pour les régions adossées au pagefile ou PAGE_NOACCESS, l'appel est en fait un no-op. Le champ `IoStatus.Information` reporte le nombre d'octets effectivement écrits.

Usage courant par les malwares

Utilisé dans les chaînes de persistance et de ransomware qui modifient des artefacts sur disque via une vue memory-mapped plutôt que `WriteFile` : l'attaquant mappe un exécutable, un INI, un XML de tâche planifiée ou la liste des LSA Notification Packages en `PAGE_READWRITE`, patche les octets et appelle `NtFlushVirtualMemory` pour forcer l'écriture *maintenant* au lieu d'attendre le lazy writer — important quand l'étape suivante (reboot, redémarrage de service, exec immédiat) doit voir la modif sur disque. Aussi vu dans des chaînes de credential-theft style `MiniDumpWriteDump` qui mappent et éditent le fichier de dump in-place. Certaines familles de ransomware appellent ce syscall pour s'assurer que les octets chiffrés atteignent les plateaux avant de supprimer les shadow copies et de forcer un reboot.

Opportunités de détection

Sysmon Event 11 (FileCreate) ne se déclenche pas sur un flush — le fichier existe déjà. La télémétrie la plus fiable est l'event ETW `Microsoft-Windows-Kernel-FileIO` `FileIo/OperationEnd` pour les opérations `WRITE` dont les `IrpFlags` indiquent du paging-IO, corrélée à un processus qui a récemment obtenu une section accessible en écriture sur un fichier sensible (exécutable de `\System32`, XML de tâche planifiée, binaire référencé par `ImagePath` dans `\Registry\Machine\System\CurrentControlSet\Services\*`). Les EDR qui hookent `NtCreateSection` contre les chemins à forte valeur puis suivent les `NtFlushVirtualMemory` subséquents contre ces vues attrapent le pattern de patch in-place.

Exemples de syscalls directs

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
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20