> Windows Syscalls
ntoskrnl.exeT1497T1486T1106

NtUnlockFile

Releases a previously-acquired byte-range lock on an open file.

Prototype

NTSTATUS NtUnlockFile(
  HANDLE           FileHandle,
  PIO_STATUS_BLOCK IoStatusBlock,
  PLARGE_INTEGER   ByteOffset,
  PLARGE_INTEGER   Length,
  ULONG            Key
);

Arguments

NameTypeDirDescription
FileHandleHANDLEinHandle to the open file that owns the lock. Must be the same handle that acquired it.
IoStatusBlockPIO_STATUS_BLOCKoutReceives final NTSTATUS and Information (always 0 for NtUnlockFile).
ByteOffsetPLARGE_INTEGERinStarting byte offset of the range to release. Must exactly match the original NtLockFile call.
LengthPLARGE_INTEGERinLength in bytes of the range to release. Must exactly match the original NtLockFile.
KeyULONGinCookie that identifies which lock to release among overlapping locks held by the same handle.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x1ADwin10-1507
Win10 16070x1B6win10-1607
Win10 17030x1BCwin10-1703
Win10 17090x1C0win10-1709
Win10 18030x1C2win10-1803
Win10 18090x1C3win10-1809
Win10 19030x1C4win10-1903
Win10 19090x1C4win10-1909
Win10 20040x1CAwin10-2004
Win10 20H20x1CAwin10-20h2
Win10 21H10x1CAwin10-21h1
Win10 21H20x1CCwin10-21h2
Win10 22H20x1CCwin10-22h2
Win11 21H20x1D6win11-21h2
Win11 22H20x1DAwin11-22h2
Win11 23H20x1DAwin11-23h2
Win11 24H20x1DDwin11-24h2
Server 20160x1B6winserver-2016
Server 20190x1C3winserver-2019
Server 20220x1D2winserver-2022
Server 20250x1DDwinserver-2025

Kernel module

ntoskrnl.exeNtUnlockFile

Related APIs

UnlockFileUnlockFileExNtLockFileNtClose

Syscall stub

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

Mirror of NtLockFile. The unlock range must *exactly* match a previously-acquired range — there is no partial-overlap unlock, no "unlock everything" shortcut. Calling with a non-matching range returns STATUS_RANGE_NOT_LOCKED. Locks are also released implicitly when the FileHandle is closed (NtClose), which is how almost every legitimate unlock happens — explicit NtUnlockFile is mostly used by long-running database engines and Office applications that release per-record locks while keeping the file open.

Common malware usage

On its own, NtUnlockFile is uninteresting — it's just the cleanup half of NtLockFile abuse. In practice it appears as the closing step of two patterns: (a) the self-locking anti-analysis stub unlocks before exiting so that an uninstaller / updater can rewrite the binary cleanly, and (b) ransomware that locked its ransom-note during encryption unlocks once the encryption phase completes so the victim can read it. Honest signal: there is essentially no public reporting of NtUnlockFile being a discriminating IOC by itself, and most ransomware skips the explicit unlock and just closes the handle.

Detection opportunities

Volume profile and detection story are identical to NtLockFile — same ETW provider, same FltMgr minifilter hook point (IRP_MJ_LOCK_CONTROL covers both lock and unlock). The blue-team value of NtUnlockFile alerts is low; the value is in *correlation* with a preceding NtLockFile on a sensitive target. EDRs that already alert on the lock event don't gain much by also alerting on the unlock. Worth tracking when investigating ransomware artifacts post-incident: a sudden burst of NtUnlockFile against many user-document handles correlates with the end of the encryption sweep.

Direct syscall examples

cRelease a whole-file lock before exit

// Pair-of-pair: matches the NtLockFile call that took the whole-file lock.
IO_STATUS_BLOCK iosb;
LARGE_INTEGER off = { .QuadPart = 0 };
LARGE_INTEGER len = { .QuadPart = 0x7FFFFFFFFFFFFFFFLL };

NTSTATUS st = NtUnlockFile(hSelf, &iosb, &off, &len, 0);
if (st == STATUS_RANGE_NOT_LOCKED) {
    // Some other code already unlocked it (or the offsets don't match).
}

asmx64 direct stub (Win11 24H2 SSN 0x1DD)

NtUnlockFile PROC
    mov  r10, rcx
    mov  eax, 1DDh
    syscall
    ret
NtUnlockFile ENDP

rustRelease ransom-note lock after encryption sweep

// Cargo: ntapi = "0.4"
unsafe {
    let off: i64 = 0;
    let len: i64 = i64::MAX;
    let mut iosb = zeroed();
    let st = NtUnlockFile(h_note,
        &mut iosb,
        &off as *const _ as _,
        &len as *const _ as _,
        0);
    // STATUS_RANGE_NOT_LOCKED is benign here — handle close would have done it anyway.
    let _ = st;
}

MITRE ATT&CK mappings

Last verified: 2026-05-20