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
| Name | Type | Dir | Description |
|---|---|---|---|
| FileHandle | HANDLE | in | Handle auf die offene Datei, die den Lock hält. Muss dasselbe Handle sein, das ihn erworben hat. |
| IoStatusBlock | PIO_STATUS_BLOCK | out | Empfängt den finalen NTSTATUS und Information (bei NtUnlockFile stets 0). |
| ByteOffset | PLARGE_INTEGER | in | Anfangs-Byte-Offset des freizugebenden Bereichs. Muss exakt mit dem ursprünglichen NtLockFile-Aufruf übereinstimmen. |
| Length | PLARGE_INTEGER | in | Länge in Bytes des freizugebenden Bereichs. Muss exakt mit dem ursprünglichen NtLockFile übereinstimmen. |
| Key | ULONG | in | Cookie, das identifiziert, welcher von mehreren überlappenden Locks desselben Handles freigegeben werden soll. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x1AD | win10-1507 |
| Win10 1607 | 0x1B6 | win10-1607 |
| Win10 1703 | 0x1BC | win10-1703 |
| Win10 1709 | 0x1C0 | win10-1709 |
| Win10 1803 | 0x1C2 | win10-1803 |
| Win10 1809 | 0x1C3 | win10-1809 |
| Win10 1903 | 0x1C4 | win10-1903 |
| Win10 1909 | 0x1C4 | win10-1909 |
| Win10 2004 | 0x1CA | win10-2004 |
| Win10 20H2 | 0x1CA | win10-20h2 |
| Win10 21H1 | 0x1CA | win10-21h1 |
| Win10 21H2 | 0x1CC | win10-21h2 |
| Win10 22H2 | 0x1CC | win10-22h2 |
| Win11 21H2 | 0x1D6 | win11-21h2 |
| Win11 22H2 | 0x1DA | win11-22h2 |
| Win11 23H2 | 0x1DA | win11-23h2 |
| Win11 24H2 | 0x1DD | win11-24h2 |
| Server 2016 | 0x1B6 | winserver-2016 |
| Server 2019 | 0x1C3 | winserver-2019 |
| Server 2022 | 0x1D2 | winserver-2022 |
| Server 2025 | 0x1DD | winserver-2025 |
Kernel-Modul
Verwandte APIs
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.
Erkennungsmö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 ENDPrustRelease 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