NtCreateFile
Creates or opens a file, directory, device, or named pipe — every dropper's first call to disk.
Prototype
NTSTATUS NtCreateFile( PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| FileHandle | PHANDLE | out | Receives the handle to the created or opened file. |
| DesiredAccess | ACCESS_MASK | in | Access mask, e.g. GENERIC_WRITE | SYNCHRONIZE, FILE_GENERIC_READ, DELETE. |
| ObjectAttributes | POBJECT_ATTRIBUTES | in | OBJECT_ATTRIBUTES holding the NT path (e.g. \??\C:\Windows\Temp\a.exe). |
| IoStatusBlock | PIO_STATUS_BLOCK | out | Receives final NTSTATUS and Information field (FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN…). |
| AllocationSize | PLARGE_INTEGER | in | Optional initial allocation size. NULL leaves it to the filesystem. |
| FileAttributes | ULONG | in | Attributes for newly created files: FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM. |
| ShareAccess | ULONG | in | Sharing mode: FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE or 0 for exclusive. |
| CreateDisposition | ULONG | in | What to do if file exists: FILE_CREATE, FILE_OPEN, FILE_OPEN_IF, FILE_OVERWRITE, FILE_OVERWRITE_IF, FILE_SUPERSEDE. |
| CreateOptions | ULONG | in | Options: FILE_SYNCHRONOUS_IO_NONALERT, FILE_NON_DIRECTORY_FILE, FILE_DELETE_ON_CLOSE… |
| EaBuffer | PVOID | in | Extended Attributes buffer. Usually NULL. |
| EaLength | ULONG | in | Size of EaBuffer in bytes. 0 when EaBuffer is NULL. |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x55 | win10-1507 |
| Win10 1607 | 0x55 | win10-1607 |
| Win10 1703 | 0x55 | win10-1703 |
| Win10 1709 | 0x55 | win10-1709 |
| Win10 1803 | 0x55 | win10-1803 |
| Win10 1809 | 0x55 | win10-1809 |
| Win10 1903 | 0x55 | win10-1903 |
| Win10 1909 | 0x55 | win10-1909 |
| Win10 2004 | 0x55 | win10-2004 |
| Win10 20H2 | 0x55 | win10-20h2 |
| Win10 21H1 | 0x55 | win10-21h1 |
| Win10 21H2 | 0x55 | win10-21h2 |
| Win10 22H2 | 0x55 | win10-22h2 |
| Win11 21H2 | 0x55 | win11-21h2 |
| Win11 22H2 | 0x55 | win11-22h2 |
| Win11 23H2 | 0x55 | win11-23h2 |
| Win11 24H2 | 0x55 | win11-24h2 |
| Server 2016 | 0x55 | winserver-2016 |
| Server 2019 | 0x55 | winserver-2019 |
| Server 2022 | 0x55 | winserver-2022 |
| Server 2025 | 0x55 | winserver-2025 |
Kernel module
Related APIs
Syscall stub
4C 8B D1 mov r10, rcx B8 55 00 00 00 mov eax, 0x55 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
Undocumented notes
NtCreateFile takes 11 parameters — more than any other commonly-abused syscall — and is the entry point underneath `CreateFileW`, `OpenFile`, `_open`, and most filesystem-touching CRT helpers. SSN `0x55` has not moved since Windows 7. The path uses the NT namespace (`\??\C:\path` or `\Device\HarddiskVolume3\path`); supplying a non-Win32 path is a common trick to confuse minifilter rules keyed on DOS paths. On x64 only the first four parameters travel in registers (RCX, RDX, R8, R9) — the rest are passed on the stack after the 32-byte home space, which matters when hand-rolling a stub.
Common malware usage
The universal dropper primitive: write second-stage payloads to `%PROGRAMDATA%`, `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\`, `%APPDATA%\Microsoft\Templates\Normal.dotm` (Office template persistence, T1137.001), or `C:\Users\Public\` to dodge per-user roaming profiles. Combined with `FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM` and a leading `.` filename, files vanish from Explorer's default view. `FILE_FLAG_DELETE_ON_CLOSE` (via `FILE_DELETE_ON_CLOSE` CreateOption) is used by self-deleting droppers, and `\\.\PHYSICALDRIVE0` access is the entry point for boot-record overwriting wipers (Petya, HermeticWiper).
Detection opportunities
Sysmon Event ID 11 (FileCreate) is the cornerstone — fires with image path of the creator and the full target path. Event ID 23 (FileDelete) and 26 (FileDeleteDetected) catch self-deletion attempts. Microsoft-Windows-Kernel-File ETW (`{EDD08927-9CC4-4E65-B970-C2560FB5C289}`) provides the same data without Sysmon. Minifilter drivers (FltMgr) registered by EDRs see every NtCreateFile with full create-context including pre-create and post-create callbacks — most EDRs use this rather than user-mode hooks, so direct syscalls do *not* hide file drops. Hunt on writes to Startup folders, `Templates\Normal.dotm`, IFEO-adjacent paths, and `\Device\PhysicalDriveN` opens by non-system processes.
Direct syscall examples
cDrop a hidden payload to %PROGRAMDATA%
// Create C:\ProgramData\impl.bin hidden+system, overwrite if exists.
UNICODE_STRING path;
RtlInitUnicodeString(&path, L"\\??\\C:\\ProgramData\\impl.bin");
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);
IO_STATUS_BLOCK iosb = {0};
HANDLE hFile = NULL;
NTSTATUS s = NtCreateFile(
&hFile,
GENERIC_WRITE | SYNCHRONIZE,
&oa,
&iosb,
NULL, // AllocationSize
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
FILE_SHARE_READ,
FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
NULL, 0);asmDirect stub (SSN 0x55) — stack args
; NtCreateFile has 11 args. Caller pushes args 5..11 on the stack;
; the syscall stub itself is the canonical 4-instr form.
NtCreateFile PROC
mov r10, rcx
mov eax, 55h
syscall
ret
NtCreateFile ENDPrustSelf-deleting marker file
// Sets FILE_DELETE_ON_CLOSE so the file vanishes when the handle is closed.
use ntapi::ntioapi::{NtCreateFile, IO_STATUS_BLOCK};
use ntapi::ntrtl::RtlInitUnicodeString;
use winapi::shared::ntdef::{OBJECT_ATTRIBUTES, OBJ_CASE_INSENSITIVE, UNICODE_STRING};
use winapi::um::winnt::{DELETE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, SYNCHRONIZE};
const FILE_CREATE: u32 = 0x2;
const FILE_SYNCHRONOUS_IO_NONALERT: u32 = 0x20;
const FILE_DELETE_ON_CLOSE: u32 = 0x1000;
const FILE_NON_DIRECTORY_FILE: u32 = 0x40;
pub unsafe fn touch_ephemeral(nt_path: *const u16) {
let mut us: UNICODE_STRING = core::mem::zeroed();
RtlInitUnicodeString(&mut us, nt_path);
let mut oa = OBJECT_ATTRIBUTES {
Length: core::mem::size_of::<OBJECT_ATTRIBUTES>() as u32,
RootDirectory: core::ptr::null_mut(),
ObjectName: &mut us,
Attributes: OBJ_CASE_INSENSITIVE,
SecurityDescriptor: core::ptr::null_mut(),
SecurityQualityOfService: core::ptr::null_mut(),
};
let mut iosb: IO_STATUS_BLOCK = core::mem::zeroed();
let mut h = core::ptr::null_mut();
NtCreateFile(
&mut h,
DELETE | SYNCHRONIZE,
&mut oa,
&mut iosb,
core::ptr::null_mut(),
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE,
core::ptr::null_mut(),
0,
);
}MITRE ATT&CK mappings
- T1564.001Hidden Files and Directories
- T1547.001Registry Run Keys / Startup Folder
- T1137.001Office Template Macros
- T1106Native API
Last verified: 2026-05-20