NtOpenFile
Opens a handle to an existing file or device — the lighter no-create counterpart of NtCreateFile.
Prototype
NTSTATUS NtOpenFile( PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| FileHandle | PHANDLE | out | Receives the handle to the opened file or device on success. |
| DesiredAccess | ACCESS_MASK | in | Requested access rights (FILE_READ_DATA, FILE_GENERIC_READ, SYNCHRONIZE, READ_CONTROL, etc.). |
| ObjectAttributes | POBJECT_ATTRIBUTES | in | NT-namespace path, e.g. \??\C:\Windows\System32\config\SAM or \Device\HarddiskVolume1\... |
| IoStatusBlock | PIO_STATUS_BLOCK | out | Receives the final NTSTATUS and Information field (FILE_OPENED here, vs FILE_CREATED for NtCreateFile). |
| ShareAccess | ULONG | in | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE mask granted to concurrent openers. |
| OpenOptions | ULONG | in | FILE_SYNCHRONOUS_IO_NONALERT, FILE_NON_DIRECTORY_FILE, FILE_OPEN_REPARSE_POINT, FILE_OPEN_FOR_BACKUP_INTENT, etc. |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x33 | win10-1507 |
| Win10 1607 | 0x33 | win10-1607 |
| Win10 1703 | 0x33 | win10-1703 |
| Win10 1709 | 0x33 | win10-1709 |
| Win10 1803 | 0x33 | win10-1803 |
| Win10 1809 | 0x33 | win10-1809 |
| Win10 1903 | 0x33 | win10-1903 |
| Win10 1909 | 0x33 | win10-1909 |
| Win10 2004 | 0x33 | win10-2004 |
| Win10 20H2 | 0x33 | win10-20h2 |
| Win10 21H1 | 0x33 | win10-21h1 |
| Win10 21H2 | 0x33 | win10-21h2 |
| Win10 22H2 | 0x33 | win10-22h2 |
| Win11 21H2 | 0x33 | win11-21h2 |
| Win11 22H2 | 0x33 | win11-22h2 |
| Win11 23H2 | 0x33 | win11-23h2 |
| Win11 24H2 | 0x33 | win11-24h2 |
| Server 2016 | 0x33 | winserver-2016 |
| Server 2019 | 0x33 | winserver-2019 |
| Server 2022 | 0x33 | winserver-2022 |
| Server 2025 | 0x33 | winserver-2025 |
Kernel module
Related APIs
Syscall stub
4C 8B D1 mov r10, rcx B8 33 00 00 00 mov eax, 0x33 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
NtOpenFile is functionally equivalent to `NtCreateFile` with `CreateDisposition = FILE_OPEN` but with fewer arguments — no allocation size, no extended attributes, no file attributes. It cannot create files. SSN `0x33` has been stable since Windows 10 1507. The Win32 `CreateFileW` wrapper always dispatches to `NtCreateFile`; user-mode code that prefers NtOpenFile is typically deliberately bypassing the create path to avoid EDR hooks that focus on NtCreateFile, or to keep the call signature small for direct-syscall stubs.
Common malware usage
Use cases cluster around **stealthy filesystem enumeration and read**. Pairing NtOpenFile with NtQueryDirectoryFile and NtReadFile lets a loader walk directories and slurp config / target files entirely via Nt* surface, sidestepping `kernel32!CreateFileW` and `FindFirstFileW` hooks that user-mode EDRs commonly inline. `FILE_OPEN_FOR_BACKUP_INTENT` combined with SeBackupPrivilege also lets the call bypass DACLs on read — useful for hive-staging chains (open `\??\C:\Windows\System32\config\SAM` directly when SYSTEM, no need to copy via VSS). NtOpenFile is also preferred for opening device objects (`\Device\PhysicalDrive0`, `\??\PIPE\...`) in tooling that explicitly wants the NT path.
Detection opportunities
NtOpenFile is far too common to alert on directly — every process makes many of these. The discriminating signal is the *target path* combined with the *opener*: a non-system process opening `\Device\PhysicalDrive*`, `\??\C:\Windows\System32\config\SAM`, `\??\C:\Windows\NTDS\ntds.dit`, or any LSASS-related path is high-confidence malicious. Sysmon Event 11 covers file *creates* but not pure opens; for opens, Microsoft-Windows-Kernel-File and Microsoft-Windows-Threat-Intelligence ETW providers are the primary telemetry, alongside EDR mini-filter callbacks at the IRP_MJ_CREATE layer.
Direct syscall examples
asmx64 direct stub
; Direct syscall stub for NtOpenFile (SSN 0x33, stable since Win10 1507)
NtOpenFile PROC
mov r10, rcx ; FileHandle
mov eax, 33h ; SSN
syscall
ret
NtOpenFile ENDPcStealthy file open + read (Nt* only)
// Open a file via the NT namespace and read its content without touching
// kernel32!CreateFileW / ReadFile — useful for loaders that want to skip
// common user-mode hook surfaces.
#include <windows.h>
#include <winternl.h>
#define FILE_OPEN 0x00000001
#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
int ReadViaNtOpen(LPCWSTR ntpath, void *buf, ULONG len) {
UNICODE_STRING us; RtlInitUnicodeString(&us, ntpath);
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, NULL, NULL);
IO_STATUS_BLOCK iosb = {0};
HANDLE h = NULL;
NTSTATUS s = NtOpenFile(&h, FILE_GENERIC_READ | SYNCHRONIZE,
&oa, &iosb,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (s < 0) return s;
s = NtReadFile(h, NULL, NULL, NULL, &iosb, buf, len, NULL, NULL);
NtClose(h);
return (int)iosb.Information;
}rustwindows-sys NtOpenFile call
// Cargo: windows-sys = { version = "0.59", features = [
// "Win32_Foundation", "Wdk_Foundation", "Wdk_Storage_FileSystem",
// "Win32_System_WindowsProgramming",
// ] }
use windows_sys::Wdk::Storage::FileSystem::NtOpenFile;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::WindowsProgramming::OBJECT_ATTRIBUTES;
use windows_sys::Wdk::Foundation::OBJECT_ATTRIBUTES as OA;
use windows_sys::Win32::System::IO::IO_STATUS_BLOCK;
unsafe fn open_for_read(oa: *mut OA) -> Option<HANDLE> {
let mut h: HANDLE = std::ptr::null_mut();
let mut iosb: IO_STATUS_BLOCK = std::mem::zeroed();
let s = NtOpenFile(
&mut h,
0x80000000 /* GENERIC_READ */ | 0x00100000 /* SYNCHRONIZE */,
oa as *mut OBJECT_ATTRIBUTES,
&mut iosb,
0x00000003 /* SHARE_READ|WRITE */,
0x00000020 /* FILE_SYNCHRONOUS_IO_NONALERT */,
);
if s == 0 { Some(h) } else { None }
}MITRE ATT&CK mappings
Last verified: 2026-05-20