> Windows Syscalls
ntoskrnl.exeT1486T1561.001T1106

NtWriteFile

Écrit des données dans un fichier, pipe ou périphérique ouvert — pendant noyau de NtCreateFile pour déposer un payload.

Prototype

NTSTATUS NtWriteFile(
  HANDLE           FileHandle,
  HANDLE           Event,
  PIO_APC_ROUTINE  ApcRoutine,
  PVOID            ApcContext,
  PIO_STATUS_BLOCK IoStatusBlock,
  PVOID            Buffer,
  ULONG            Length,
  PLARGE_INTEGER   ByteOffset,
  PULONG           Key
);

Arguments

NameTypeDirDescription
FileHandleHANDLEinHandle ouvert par NtCreateFile/NtOpenFile avec GENERIC_WRITE ou FILE_WRITE_DATA.
EventHANDLEinÉvénement optionnel signalé à la fin d'une écriture async. NULL pour les handles synchrones.
ApcRoutinePIO_APC_ROUTINEinAPC optionnel livré à la complétion. Quasi toujours NULL en dehors d'E/S superposées.
ApcContextPVOIDinContexte transmis à ApcRoutine. NULL si ApcRoutine est NULL.
IoStatusBlockPIO_STATUS_BLOCKoutReçoit le NTSTATUS final et le champ Information avec le nombre d'octets écrits.
BufferPVOIDinPointeur vers les données à écrire.
LengthULONGinNombre d'octets à écrire depuis Buffer.
ByteOffsetPLARGE_INTEGERinOffset dans le fichier, ou FILE_USE_FILE_POINTER_POSITION (-2) pour la position courante.
KeyPULONGinClé optionnelle de verrou par plage d'octets. Quasi toujours NULL.

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 15070x8win10-1507
Win10 16070x8win10-1607
Win10 17030x8win10-1703
Win10 17090x8win10-1709
Win10 18030x8win10-1803
Win10 18090x8win10-1809
Win10 19030x8win10-1903
Win10 19090x8win10-1909
Win10 20040x8win10-2004
Win10 20H20x8win10-20h2
Win10 21H10x8win10-21h1
Win10 21H20x8win10-21h2
Win10 22H20x8win10-22h2
Win11 21H20x8win11-21h2
Win11 22H20x8win11-22h2
Win11 23H20x8win11-23h2
Win11 24H20x8win11-24h2
Server 20160x8winserver-2016
Server 20190x8winserver-2019
Server 20220x8winserver-2022
Server 20250x8winserver-2025

Module noyau

ntoskrnl.exeNtWriteFile

APIs liées

WriteFileWriteFileExNtReadFileNtCreateFileNtSetInformationFileFlushFileBuffers

Stub du syscall

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

SSN `0x8` — l'un des plus bas, inchangé depuis Windows 7 — rendant NtWriteFile facile à appeler sans résolution dynamique. L'API a 9 paramètres, dont seuls FileHandle, IoStatusBlock, Buffer, Length et ByteOffset sont couramment non-NULL. Si le handle a été ouvert avec `FILE_SYNCHRONOUS_IO_NONALERT` (cas typique), l'appel bloque jusqu'à la fin de l'écriture et l'IoStatusBlock est rempli avant le retour. L'acheminement passe par IopXxxControlFile → IRP_MJ_WRITE du driver, donc tous les filtres de système de fichiers et de stockage de la pile voient l'écriture.

Usage courant par les malwares

Couplé à NtCreateFile, il constitue à lui seul la chaîne de mise à disque : ouvrir en FILE_OVERWRITE_IF, NtWriteFile du stage suivant chiffré, fermer. Les ransomwares s'en servent pendant le chiffrement (ouvrir l'original, NtReadFile, chiffrer, NtWriteFile par-dessus ou vers un compagnon `.locked`). Les wipers l'utilisent pour zéroter `\Device\PhysicalDriveN` ou écraser les fichiers de hive du registre (HermeticWiper, CaddyWiper). Les loaders qui écrivent dans `%APPDATA%\Microsoft\Templates\Normal.dotm` ou un raccourci du dossier Startup bouclent la persistance sans jamais toucher à kernel32!WriteFile.

Opportunités de détection

Contrairement à NtCreateFile, NtWriteFile produit peu de télémétrie dédiée : la *création* déclenche Sysmon 11 / Kernel-File `Create`, mais l'événement par écriture est trop bruyant pour être logué par défaut. Les EDR se placent dans la couche minifilter et voient les données effectivement écrites, ce qui permet aux moteurs YARA-on-write et aux leurres ransomware de fonctionner. Microsoft-Windows-Kernel-File event 12 (`Write`) existe mais n'est généralement activé qu'en réponse à incident en raison du volume. L'asymétrie est opérationnelle : les défenseurs détectent les ransomwares par *ce qui* est écrit (contenu à haute entropie, extensions retournées, renommages en masse), pas par le nombre d'appels NtWriteFile. Corréler avec NtSetInformationFile/FileDispositionInformation pour saisir le renommage ou la suppression qui suit.

Exemples de syscalls directs

cWrite payload to a freshly-created file

// After NtCreateFile gave us a synchronous, writable handle:
IO_STATUS_BLOCK iosb = {0};
LARGE_INTEGER offset = { .QuadPart = 0 };
NTSTATUS s = NtWriteFile(
    hFile,
    NULL, NULL, NULL,         // no event, no APC
    &iosb,
    payload, payloadLen,
    &offset,                  // write at start of file
    NULL);                    // no lock key
if (NT_SUCCESS(s)) {
    // iosb.Information == bytes written
}

asmDirect stub (SSN 0x8)

NtWriteFile PROC
    mov  r10, rcx
    mov  eax, 8
    syscall
    ret
NtWriteFile ENDP

rustAppend to a log device via ntapi

use ntapi::ntioapi::{NtWriteFile, IO_STATUS_BLOCK};

pub unsafe fn write_all(handle: *mut core::ffi::c_void, data: &[u8]) -> i32 {
    let mut iosb: IO_STATUS_BLOCK = core::mem::zeroed();
    // -2 == FILE_USE_FILE_POINTER_POSITION
    let mut offset: i64 = -2;
    NtWriteFile(
        handle,
        core::ptr::null_mut(),
        None,
        core::ptr::null_mut(),
        &mut iosb,
        data.as_ptr() as *mut _,
        data.len() as u32,
        &mut offset as *mut _ as *mut _,
        core::ptr::null_mut(),
    )
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20