NtClose
Ferme un handle d'objet noyau (fichier, clé, événement, processus, thread, section, etc.).
Prototype
NTSTATUS NtClose( HANDLE Handle );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| Handle | HANDLE | in | Handle vers l'objet noyau à fermer. Doit être un handle ouvert valide dans le processus courant. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0xF | win10-1507 |
| Win10 1607 | 0xF | win10-1607 |
| Win10 1703 | 0xF | win10-1703 |
| Win10 1709 | 0xF | win10-1709 |
| Win10 1803 | 0xF | win10-1803 |
| Win10 1809 | 0xF | win10-1809 |
| Win10 1903 | 0xF | win10-1903 |
| Win10 1909 | 0xF | win10-1909 |
| Win10 2004 | 0xF | win10-2004 |
| Win10 20H2 | 0xF | win10-20h2 |
| Win10 21H1 | 0xF | win10-21h1 |
| Win10 21H2 | 0xF | win10-21h2 |
| Win10 22H2 | 0xF | win10-22h2 |
| Win11 21H2 | 0xF | win11-21h2 |
| Win11 22H2 | 0xF | win11-22h2 |
| Win11 23H2 | 0xF | win11-23h2 |
| Win11 24H2 | 0xF | win11-24h2 |
| Server 2016 | 0xF | winserver-2016 |
| Server 2019 | 0xF | winserver-2019 |
| Server 2022 | 0xF | winserver-2022 |
| Server 2025 | 0xF | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 0F 00 00 00 mov eax, 0xF 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
NtClose porte le SSN `0xF` sans changement depuis Windows 10 1507 jusqu'à Windows 11 24H2 — l'un des numéros les plus stables. Il libère la référence sur l'objet sous-jacent via ObCloseHandle et déclenche l'exception de débogage STATUS_INVALID_HANDLE (0xC0000008) lorsqu'il est appelé sur un handle bidon avec un débogueur attaché et FLG_ENABLE_CLOSE_EXCEPTIONS activé. Sa forme est triviale, mais c'est l'un des syscalls les plus appelés sur un système actif, ce qui lui donne un mauvais ratio signal/bruit pour la détection et un excellent terrain de dissimulation.
Usage courant par les malwares
Deux usages distincts : (1) hygiène de routine — tout loader, injecteur et voleur d'identifiants doit relâcher ses handles sous peine de fuites repérables par les outils de monitoring ; (2) anti-débogage — appeler NtClose avec un handle invalide (ex. 0xDEADBEEF) sous un débogueur usermode déclenche STATUS_INVALID_HANDLE intercepté par le débogueur, ce qui permet au malware d'abandonner ou de bifurquer vers une logique de leurre. Le test coûte rien, ne demande aucun import au-delà de ntdll, et survit à la plupart des unpackers automatiques.
Opportunités de détection
NtClose en lui-même est trop bruyant pour servir d'alerte. Pivots utiles : séquences à haut débit de NtClose avec retours non SUCCESS (heuristique pour la sonde anti-debug), ratios NtOpen*/NtClose déséquilibrés par processus (fuites de handle), et ETW Microsoft-Windows-Kernel-Audit-API-Calls. Les EDR hookent souvent NtClose dans ntdll pour la cohérence du comptage de références ; les syscalls directs contournent ce hook mais laissent des traces ObCloseHandle visibles côté minifilter ou callback kernel.
Exemples de syscalls directs
asmx64 direct stub
; Direct syscall stub for NtClose (SSN 0xF, all builds)
NtClose PROC
mov r10, rcx ; syscall convention
mov eax, 0Fh ; SSN
syscall
ret
NtClose ENDPcINVALID_HANDLE anti-debug probe
// If a debugger is attached and FLG_ENABLE_CLOSE_EXCEPTIONS is set in the
// process flags, NtClose on a bogus handle raises STATUS_INVALID_HANDLE.
// The debugger swallows the exception first; the malware sees a return code.
#include <windows.h>
typedef NTSTATUS (NTAPI *pNtClose)(HANDLE);
BOOL IsDebuggerPresentViaNtClose(void) {
pNtClose NtClose = (pNtClose)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtClose");
__try {
NtClose((HANDLE)0xDEADBEEF);
} __except (EXCEPTION_EXECUTE_HANDLER) {
return FALSE; // exception delivered to us -> no debugger
}
return TRUE; // debugger ate the exception
}rustwindows-sys cleanup
// Cargo: windows-sys = "0.59" (Win32_Foundation, Win32_System_Threading)
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
pub struct OwnedHandle(pub HANDLE);
impl Drop for OwnedHandle {
fn drop(&mut self) {
if !self.0.is_null() && self.0 as isize != -1 {
// CloseHandle wraps NtClose; use NtClose directly to bypass
// ntdll user-mode hooks on EDR-monitored hosts.
unsafe { CloseHandle(self.0) };
}
}
}Mappings MITRE ATT&CK
Last verified: 2026-05-20