NtUnlockFile
Libère un verrou de plage d'octets précédemment acquis sur un fichier ouvert.
Prototype
NTSTATUS NtUnlockFile( HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER ByteOffset, PLARGE_INTEGER Length, ULONG Key );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| FileHandle | HANDLE | in | Handle vers le fichier ouvert détenant le verrou. Doit être le même handle qui l'a acquis. |
| IoStatusBlock | PIO_STATUS_BLOCK | out | Reçoit le NTSTATUS final et Information (toujours 0 pour NtUnlockFile). |
| ByteOffset | PLARGE_INTEGER | in | Offset de début (en octets) de la plage à libérer. Doit correspondre exactement à l'appel NtLockFile original. |
| Length | PLARGE_INTEGER | in | Longueur en octets de la plage à libérer. Doit correspondre exactement au NtLockFile original. |
| Key | ULONG | in | Cookie identifiant quel verrou libérer parmi les verrous chevauchants détenus par le même handle. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | 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 |
Module noyau
APIs liées
Stub du syscall
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
Notes non documentées
Miroir de NtLockFile. La plage à débloquer doit *exactement* correspondre à une plage précédemment acquise — pas de déblocage de chevauchement partiel, pas de raccourci « tout débloquer ». Un appel avec une plage non-correspondante renvoie STATUS_RANGE_NOT_LOCKED. Les verrous sont aussi libérés implicitement à la fermeture du FileHandle (NtClose), c'est ainsi que se passe presque toute libération légitime — NtUnlockFile explicite est surtout utilisé par les moteurs de base de données long-running et Office qui libèrent des verrous par enregistrement en gardant le fichier ouvert.
Usage courant par les malwares
Seul, NtUnlockFile est peu intéressant — c'est juste la moitié nettoyage d'un abus de NtLockFile. En pratique il apparaît comme étape finale de deux motifs : (a) le stub anti-analyse auto-verrouillé déverrouille avant de sortir pour qu'un désinstalleur / updater puisse réécrire le binaire proprement, et (b) un rançongiciel qui a verrouillé sa note pendant le chiffrement déverrouille une fois la phase de chiffrement terminée pour que la victime puisse la lire. Signal honnête : il n'existe quasiment aucun rapport public faisant de NtUnlockFile un IOC discriminant par lui-même, et la plupart des rançongiciels sautent le déverrouillage explicite et se contentent de fermer le handle.
Opportunités de détection
Profil de volume et histoire de détection identiques à NtLockFile — même fournisseur ETW, même point de hook minifilter FltMgr (IRP_MJ_LOCK_CONTROL couvre lock et unlock). La valeur blue-team d'alertes NtUnlockFile est faible ; la valeur est dans la *corrélation* avec un NtLockFile précédent sur une cible sensible. Les EDR qui alertent déjà sur l'événement lock ne gagnent pas grand-chose à alerter aussi sur l'unlock. À suivre lors d'investigations post-incident rançongiciel : une rafale soudaine de NtUnlockFile contre de nombreux handles de documents utilisateur corrèle avec la fin de la passe de chiffrement.
Exemples de syscalls directs
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;
}Mappings MITRE ATT&CK
Last verified: 2026-05-20