NtCreateFile
Crea o abre un archivo, directorio, dispositivo o canal con nombre — primera llamada a disco de todo dropper.
Prototipo
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 );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| FileHandle | PHANDLE | out | Recibe el handle al archivo creado o abierto. |
| DesiredAccess | ACCESS_MASK | in | Máscara de acceso, p. ej. GENERIC_WRITE | SYNCHRONIZE, FILE_GENERIC_READ, DELETE. |
| ObjectAttributes | POBJECT_ATTRIBUTES | in | OBJECT_ATTRIBUTES con la ruta NT (p. ej. \??\C:\Windows\Temp\a.exe). |
| IoStatusBlock | PIO_STATUS_BLOCK | out | Recibe el NTSTATUS final y el campo Information (FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN…). |
| AllocationSize | PLARGE_INTEGER | in | Tamaño inicial opcional. NULL deja la decisión al sistema de archivos. |
| FileAttributes | ULONG | in | Atributos para archivos creados: FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM. |
| ShareAccess | ULONG | in | Modo de compartición: FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE o 0 para exclusivo. |
| CreateDisposition | ULONG | in | Qué hacer si el archivo existe: FILE_CREATE, FILE_OPEN, FILE_OPEN_IF, FILE_OVERWRITE, FILE_OVERWRITE_IF, FILE_SUPERSEDE. |
| CreateOptions | ULONG | in | Opciones: FILE_SYNCHRONOUS_IO_NONALERT, FILE_NON_DIRECTORY_FILE, FILE_DELETE_ON_CLOSE… |
| EaBuffer | PVOID | in | Búfer de Extended Attributes. Normalmente NULL. |
| EaLength | ULONG | in | Tamaño de EaBuffer en bytes. 0 si EaBuffer es NULL. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | 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 |
Módulo del kernel
APIs relacionadas
Stub del syscall
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
Notas no documentadas
NtCreateFile recibe 11 parámetros — más que cualquier otro syscall abusado habitualmente — y es la entrada bajo `CreateFileW`, `OpenFile`, `_open` y la mayoría de helpers del CRT que tocan disco. El SSN `0x55` no ha cambiado desde Windows 7. La ruta usa el espacio NT (`\??\C:\path` o `\Device\HarddiskVolume3\path`); usar una ruta no-Win32 es un truco común para confundir reglas de minifilter ancladas a rutas DOS. En x64 solo los primeros cuatro parámetros viajan por registro (RCX, RDX, R8, R9) — el resto en la pila tras los 32 bytes de home space, lo que importa al escribir un stub a mano.
Uso común por malware
La primitiva universal del dropper: escribir stages secundarios en `%PROGRAMDATA%`, `%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\`, `%APPDATA%\Microsoft\Templates\Normal.dotm` (persistencia por plantilla Office, T1137.001) o `C:\Users\Public\` para evitar perfiles itinerantes. Junto a `FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM` y un nombre comenzando con `.`, el archivo desaparece de la vista por defecto del Explorador. `FILE_FLAG_DELETE_ON_CLOSE` (vía opción `FILE_DELETE_ON_CLOSE`) sirve a droppers autodestructivos, y el acceso a `\\.\PHYSICALDRIVE0` es la entrada para wipers que reescriben el MBR (Petya, HermeticWiper).
Oportunidades de detección
Sysmon Event ID 11 (FileCreate) es la piedra angular — dispara con la imagen del creador y la ruta destino completa. Event ID 23 (FileDelete) y 26 (FileDeleteDetected) atrapan la autoeliminación. ETW Microsoft-Windows-Kernel-File (`{EDD08927-9CC4-4E65-B970-C2560FB5C289}`) ofrece lo mismo sin Sysmon. Los drivers minifilter (FltMgr) que los EDR registran ven cada NtCreateFile con todo su contexto, callbacks pre y post create — la mayoría de EDR usan esta vía en lugar de hooks de usuario, así que las syscalls directas *no ocultan* los depósitos de archivos. Cazar escrituras en carpetas Startup, `Templates\Normal.dotm`, rutas próximas a IFEO, y aperturas de `\Device\PhysicalDriveN` por procesos no-sistema.
Ejemplos de syscalls directos
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,
);
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20