> Windows Syscalls
ntoskrnl.exeT1497T1486T1106

NtLockFile

Acquires a byte-range lock on an open file, optionally exclusive and optionally asynchronous.

Prototype

NTSTATUS NtLockFile(
  HANDLE           FileHandle,
  HANDLE           Event,
  PIO_APC_ROUTINE  ApcRoutine,
  PVOID            ApcContext,
  PIO_STATUS_BLOCK IoStatusBlock,
  PLARGE_INTEGER   ByteOffset,
  PLARGE_INTEGER   Length,
  ULONG            Key,
  BOOLEAN          FailImmediately,
  BOOLEAN          ExclusiveLock
);

Arguments

NameTypeDirDescription
FileHandleHANDLEinHandle to an open file opened with at least FILE_READ_DATA or FILE_WRITE_DATA.
EventHANDLEinOptional event signalled on async completion. NULL if ApcRoutine or sync wait is used.
ApcRoutinePIO_APC_ROUTINEinOptional user-mode APC fired when the lock is granted asynchronously.
ApcContextPVOIDinContext value passed back to ApcRoutine.
IoStatusBlockPIO_STATUS_BLOCKoutReceives final NTSTATUS and Information (always 0 for NtLockFile).
ByteOffsetPLARGE_INTEGERinStarting byte offset of the range to lock.
LengthPLARGE_INTEGERinLength in bytes of the range to lock. 0x7FFFFFFFFFFFFFFF effectively covers the whole file.
KeyULONGinCookie correlating this lock with a later NtUnlockFile / NtLockFile by the same key.
FailImmediatelyBOOLEANinIf TRUE, return STATUS_LOCK_NOT_GRANTED instead of waiting when the range is already locked.
ExclusiveLockBOOLEANinIf TRUE, request an exclusive (write) lock; FALSE asks for a shared (read) lock.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070xF9win10-1507
Win10 16070xFEwin10-1607
Win10 17030x102win10-1703
Win10 17090x103win10-1709
Win10 18030x104win10-1803
Win10 18090x104win10-1809
Win10 19030x105win10-1903
Win10 19090x105win10-1909
Win10 20040x10Awin10-2004
Win10 20H20x10Awin10-20h2
Win10 21H10x10Awin10-21h1
Win10 21H20x10Bwin10-21h2
Win10 22H20x10Bwin10-22h2
Win11 21H20x111win11-21h2
Win11 22H20x112win11-22h2
Win11 23H20x112win11-23h2
Win11 24H20x114win11-24h2
Server 20160xFEwinserver-2016
Server 20190x104winserver-2019
Server 20220x110winserver-2022
Server 20250x114winserver-2025

Kernel module

ntoskrnl.exeNtLockFile

Related APIs

LockFileLockFileExNtUnlockFileNtCreateFileNtReadFile

Syscall stub

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

Byte-range locks are *mandatory* on Windows (unlike most Unixes' advisory locks): an unrelated process attempting an overlapping read/write hits STATUS_FILE_LOCK_CONFLICT (ERROR_LOCK_VIOLATION 33) even if it never tried to lock. Locks are released when the file handle closes, but a process holding an open handle plus a 0…INT64_MAX exclusive lock effectively forbids any other process from reading the file content. The Key parameter lets a single owner stack many overlapping locks and release them by cookie.

Common malware usage

Two distinct abuses. (1) **Anti-analysis self-locking**: the implant opens its own backing file with FILE_SHARE_READ stripped and then takes an exclusive lock over the entire range. AV scanners attempting to read the file for static signature matching hit ERROR_LOCK_VIOLATION; many naive scanners log and skip. Combined with the lock-on-execute property of FILE_EXECUTE handles, this makes in-place deletion fail until the process exits. (2) **Ransomware UX manipulation**: encryptors take exclusive locks on the ransom-note file during the encryption phase so the victim cannot delete the note out of the way; once encryption completes the lock is released and the note becomes visible/modifiable. Some wipers also lock the MFT-equivalent metadata file to delay recovery tooling.

Detection opportunities

NtLockFile is *high volume* — every Office document, SQLite database, Outlook PST, and Git pack file uses it constantly. Useful filters: locks held over executable files (.exe/.dll/.scr) by the *same* process that opened the file are unusual outside of debuggers. ETW Microsoft-Windows-Kernel-FileIO emits FileIo/OperationEnd with Lock/Unlock subtypes but is volume-heavy. The most actionable telemetry is the *failure* side: a spike of ERROR_LOCK_VIOLATION (33) responses to legitimate scanners is a downstream indicator that something is self-locking. EDR minifilters can observe IRP_MJ_LOCK_CONTROL directly and correlate with the locking process image.

Direct syscall examples

cSelf-lock anti-analysis stub

// Re-open our own image without FILE_SHARE_READ, then take a whole-file
// exclusive lock. AV scanners that try to read it for static signature
// matching hit STATUS_FILE_LOCK_CONFLICT and move on.
HANDLE hSelf = CreateFileW(g_selfPath,
    GENERIC_READ, 0 /* no share */, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

IO_STATUS_BLOCK iosb;
LARGE_INTEGER off = { .QuadPart = 0 };
LARGE_INTEGER len = { .QuadPart = 0x7FFFFFFFFFFFFFFFLL };

NtLockFile(hSelf, NULL, NULL, NULL, &iosb,
           &off, &len, 0,
           TRUE,    // FailImmediately
           TRUE);   // ExclusiveLock

asmx64 direct stub (Win11 24H2 SSN 0x114)

NtLockFile PROC
    mov  r10, rcx
    mov  eax, 114h
    syscall
    ret
NtLockFile ENDP

rustRansom-note lock during encryption

// Cargo: ntapi = "0.4", windows-sys = "0.59"
// Hold an exclusive lock on the note while we burn through the file tree.
unsafe {
    let off: i64 = 0;
    let len: i64 = i64::MAX;
    let mut iosb = zeroed();
    let st = NtLockFile(h_note,
        null_mut(), None, null_mut(),
        &mut iosb,
        &off as *const _ as _, &len as *const _ as _,
        0,
        1,  // FailImmediately
        1); // ExclusiveLock
    assert!(st == 0);
}
// ...encrypt files...
unsafe { NtUnlockFile(h_note, &mut iosb, &off as *const _ as _, &len as *const _ as _, 0); }

MITRE ATT&CK mappings

Last verified: 2026-05-20