> Windows Syscalls
ntoskrnl.exeT1497T1486T1106

NtUnlockFile

Gibt einen zuvor erworbenen Byte-Range-Lock auf einer geöffneten Datei frei.

Prototyp

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

Argumente

NameTypeDirDescription
FileHandleHANDLEinHandle auf die offene Datei, die den Lock hält. Muss dasselbe Handle sein, das ihn erworben hat.
IoStatusBlockPIO_STATUS_BLOCKoutEmpfängt den finalen NTSTATUS und Information (bei NtUnlockFile stets 0).
ByteOffsetPLARGE_INTEGERinAnfangs-Byte-Offset des freizugebenden Bereichs. Muss exakt mit dem ursprünglichen NtLockFile-Aufruf übereinstimmen.
LengthPLARGE_INTEGERinLänge in Bytes des freizugebenden Bereichs. Muss exakt mit dem ursprünglichen NtLockFile übereinstimmen.
KeyULONGinCookie, das identifiziert, welcher von mehreren überlappenden Locks desselben Handles freigegeben werden soll.

Syscall-IDs pro 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-Modul

ntoskrnl.exeNtUnlockFile

Verwandte 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

Undokumentierte Hinweise

Spiegel zu NtLockFile. Der freizugebende Bereich muss *exakt* einem zuvor erworbenen Bereich entsprechen — kein partielles Überlappungs-Unlock, kein „alles freigeben"-Shortcut. Ein Aufruf mit nicht-passendem Bereich liefert STATUS_RANGE_NOT_LOCKED. Locks werden auch implizit beim Schließen des FileHandle (NtClose) freigegeben — so läuft praktisch jede legitime Freigabe; explizites NtUnlockFile wird vorwiegend von langlaufenden Datenbank-Engines und Office-Anwendungen verwendet, die Per-Record-Locks freigeben, während die Datei offen bleibt.

Häufige Malware-Nutzung

Für sich genommen ist NtUnlockFile uninteressant — es ist nur die Cleanup-Hälfte eines NtLockFile-Missbrauchs. Praktisch erscheint es als Abschlussschritt zweier Muster: (a) der selbst-sperrende Anti-Analysis-Stub gibt vor Exit frei, damit ein Uninstaller / Updater die Binary sauber überschreiben kann, und (b) Ransomware, die die Ransom-Note während der Verschlüsselung sperrte, gibt nach Abschluss der Phase frei, damit das Opfer sie lesen kann. Ehrliches Signal: es gibt praktisch keine öffentliche Berichterstattung, die NtUnlockFile für sich genommen als trennscharfen IOC ausweist, und die meiste Ransomware überspringt das explizite Unlock und schließt einfach das Handle.

Erkennungs­möglichkeiten

Volumenprofil und Detection-Story identisch zu NtLockFile — gleicher ETW-Provider, gleicher FltMgr-Minifilter-Hookpunkt (IRP_MJ_LOCK_CONTROL deckt Lock und Unlock ab). Der Blue-Team-Wert von NtUnlockFile-Alerts ist gering; der Wert liegt in der *Korrelation* mit einem vorausgegangenen NtLockFile auf einem sensiblen Ziel. EDRs, die bereits auf das Lock-Event alarmieren, gewinnen wenig durch zusätzliches Alarmieren auf das Unlock. Beim Post-Incident-Ransomware-Investigieren beachtenswert: ein plötzlicher Schub von NtUnlockFile gegen viele Benutzerdokument-Handles korreliert mit dem Ende des Verschlüsselungs-Sweeps.

Direkte Syscall-Beispiele

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