> Windows Syscalls
ntoskrnl.exeT1486T1561.001T1106

NtWriteFile

Schreibt Daten in eine offene Datei, Pipe oder ein Gerät — Kernel-Pendant zu NtCreateFile fürs Ablegen von Payloads.

Prototyp

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
);

Argumente

NameTypeDirDescription
FileHandleHANDLEinHandle, mit NtCreateFile/NtOpenFile geöffnet, mit GENERIC_WRITE oder FILE_WRITE_DATA.
EventHANDLEinOptionales Event, das nach Abschluss asynchroner Schreibvorgänge signalisiert wird. NULL für synchrone Handles.
ApcRoutinePIO_APC_ROUTINEinOptionale APC bei Abschluss. Außerhalb von Overlapped-I/O fast immer NULL.
ApcContextPVOIDinKontext für ApcRoutine. NULL, wenn ApcRoutine NULL ist.
IoStatusBlockPIO_STATUS_BLOCKoutErhält finalen NTSTATUS und Information-Feld mit geschriebenen Bytes.
BufferPVOIDinZeiger auf die zu schreibenden Quelldaten.
LengthULONGinAnzahl der aus Buffer zu schreibenden Bytes.
ByteOffsetPLARGE_INTEGERinDatei-Offset oder FILE_USE_FILE_POINTER_POSITION (-2) für die aktuelle Position.
KeyPULONGinOptionaler Byte-Range-Lock-Schlüssel. Fast immer NULL.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
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

Kernel-Modul

ntoskrnl.exeNtWriteFile

Verwandte APIs

WriteFileWriteFileExNtReadFileNtCreateFileNtSetInformationFileFlushFileBuffers

Syscall-Stub

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

Undokumentierte Hinweise

SSN `0x8` — eine der niedrigsten, seit Windows 7 unverändert — macht NtWriteFile ohne dynamische SSN-Auflösung leicht aufrufbar. Hinter der API stehen 9 Parameter, von denen routinemäßig nur FileHandle, IoStatusBlock, Buffer, Length und ByteOffset nicht NULL sind. War das Handle mit `FILE_SYNCHRONOUS_IO_NONALERT` geöffnet (Normalfall), blockiert der Aufruf bis zum Abschluss; der IoStatusBlock wird vor Rückkehr gefüllt. Der Weg führt über IopXxxControlFile → IRP_MJ_WRITE des Treibers; alle Dateisystem- und Storage-Filter-Treiber im Stack sehen das Schreiben.

Häufige Malware-Nutzung

Mit NtCreateFile bildet er die gesamte On-Disk-Staging-Kette: mit FILE_OVERWRITE_IF öffnen, verschlüsselten Nachfolge-Stage per NtWriteFile schreiben, schließen. Ransomware nutzt ihn beim Verschlüsseln (Original öffnen, NtReadFile, verschlüsseln, NtWriteFile zurück über die Datei oder in `.locked`-Pendants). Wiper nullen damit `\Device\PhysicalDriveN` oder überschreiben Registry-Hive-Dateien (HermeticWiper, CaddyWiper). Loader, die `%APPDATA%\Microsoft\Templates\Normal.dotm` oder eine Startup-Verknüpfung beschreiben, schließen die Persistenz-Schleife, ohne kernel32!WriteFile zu berühren.

Erkennungs­möglichkeiten

Anders als NtCreateFile produziert NtWriteFile selten eigene Telemetrie: das *Erzeugen* feuert Sysmon 11 / Kernel-File `Create`, einzelne Schreibvorgänge sind zu laut für Default-Logging. EDRs sitzen im Minifilter-Layer und sehen die tatsächlich geschriebenen Daten — Grundlage von YARA-on-Write-Engines und Ransomware-Canary-Mechaniken. Microsoft-Windows-Kernel-File Event 12 (`Write`) existiert, wird aber meist nur bei Incident-Response aktiviert. Die Asymmetrie ist operativ: Verteidiger erkennen Ransomware daran, *was* geschrieben wird (hochentropischer Inhalt, vertauschte Extensions, Massen-Renames), nicht an NtWriteFile-Zählern. Mit NtSetInformationFile/FileDispositionInformation korrelieren, um das nachfolgende Umbenennen oder Löschen zu greifen.

Direkte Syscall-Beispiele

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(),
    )
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20