NtDeleteKey
Supprime une clé de registre à la fermeture du handle — utilisé pour effacer la persistance et les artefacts d'audit après exécution.
Prototype
NTSTATUS NtDeleteKey( HANDLE KeyHandle );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| KeyHandle | HANDLE | in | Handle précédemment ouvert avec le droit d'accès DELETE (ou KEY_ALL_ACCESS). |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0xC5 | win10-1507 |
| Win10 1607 | 0xC8 | win10-1607 |
| Win10 1703 | 0xCB | win10-1703 |
| Win10 1709 | 0xCC | win10-1709 |
| Win10 1803 | 0xCD | win10-1803 |
| Win10 1809 | 0xCE | win10-1809 |
| Win10 1903 | 0xCF | win10-1903 |
| Win10 1909 | 0xCF | win10-1909 |
| Win10 2004 | 0xD3 | win10-2004 |
| Win10 20H2 | 0xD3 | win10-20h2 |
| Win10 21H1 | 0xD3 | win10-21h1 |
| Win10 21H2 | 0xD4 | win10-21h2 |
| Win10 22H2 | 0xD4 | win10-22h2 |
| Win11 21H2 | 0xD9 | win11-21h2 |
| Win11 22H2 | 0xDA | win11-22h2 |
| Win11 23H2 | 0xDA | win11-23h2 |
| Win11 24H2 | 0xDC | win11-24h2 |
| Server 2016 | 0xC8 | winserver-2016 |
| Server 2019 | 0xCE | winserver-2019 |
| Server 2022 | 0xD8 | winserver-2022 |
| Server 2025 | 0xDC | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 DC 00 00 00 mov eax, 0xDC 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
Syscall à un seul argument, mais avec une sémantique subtile : la clé est *marquée* pour suppression et n'est effectivement retirée qu'à la fermeture du handle — les lecteurs concurrents conservent l'accès jusqu'à libérer leurs propres handles. La clé doit être **feuille** (sans sous-clés), sinon l'appel retourne `STATUS_CANNOT_DELETE` ; les outils d'évasion défensive qui nettoient un arbre doivent récurser en profondeur, appelant `NtEnumerateKey` puis `NtDeleteKey` de bas en haut. Le SSN dérive notablement entre builds (0xC5 sur 1507 → 0xDC sur 24H2), résolution dynamique obligatoire.
Usage courant par les malwares
Pure **évasion défensive (T1112 + T1070)**. Deux patrons récurrents. (1) **Nettoyage de persistance post-exécution** : une fois le payload posé ou l'autorun devenu inutile, l'implant retire son propre footprint Run / RunOnce / IFEO / scheduled-task cache pour casser la reconstruction forensique. Les stubs d'auto-suppression émettent typiquement `NtDeleteKey` sur `\Registry\Machine\Software\Microsoft\Windows\CurrentVersion\Run\<implant>` et sur la clé de hijack CLSID COM précédemment posée. (2) **Altération indirecte des journaux d'évènements (T1070.001)** : alors que l'attaque canonique est `wevtutil cl` ou l'arrêt du service EventLog, plusieurs stealers (variantes LummaC2, port Win d'Atomic Stealer) annulent à la place les clés d'abonnement d'audit sous `\Registry\Machine\System\CurrentControlSet\Services\EventLog\Security\Channels\*` via NtDeleteKey, cassant la journalisation ultérieure sans déclencher le bruyant Event-ID 1102 (audit log cleared).
Opportunités de détection
L'ETW Microsoft-Windows-Kernel-Registry émet un évènement de suppression avec chemin complet et PID. Sysmon Event ID 12 avec type=DeleteKey est la capture directe. Crucialement, un EDR enregistrant `CmRegisterCallbackEx` reçoit les notifications `RegNtPreDeleteKey` et `RegNtPostDeleteKey` même quand les hooks user-mode sont contournés par syscall direct — les callbacks noyau voient l'opération post-dispatch. Chasses : suppression de tout chemin sous `\Microsoft\Windows\CurrentVersion\Run*`, `\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\*`, `\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify\*`, ou `\Services\EventLog\*`. La tamper-protection de Defender signale les écritures/suppressions sur les arbres registre liés à l'AV ; corréler avec le CreateKey/SetValue initial du même hash SHA-256 d'image fournit un graphe staging-puis-nettoyage de bout en bout.
Exemples de syscalls directs
cRemove our own Run-key persistence entry
// Open the value's parent key with DELETE access, then NtDeleteKey on the leaf.
UNICODE_STRING name;
RtlInitUnicodeString(&name,
L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\Updater");
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE hKey = NULL;
if (NT_SUCCESS(NtOpenKey(&hKey, DELETE, &oa))) {
NtDeleteKey(hKey); // marks for deletion
NtClose(hKey); // actually deletes
}asmDirect stub (SSN 0xDC, Win11 24H2)
; SSN drifts heavily; resolve dynamically before targeting multiple builds.
NtDeleteKey PROC
mov r10, rcx
mov eax, 0DCh ; Win11 24H2
syscall
ret
NtDeleteKey ENDPrustDepth-first key-tree wipe helper
use ntapi::ntregapi::{NtDeleteKey, NtEnumerateKey, NtOpenKey, KEY_BASIC_INFORMATION};
use winapi::shared::ntdef::HANDLE;
pub unsafe fn delete_tree(h_root: HANDLE) {
let mut buf = vec![0u8; 0x400];
let mut len = 0u32;
loop {
let s = NtEnumerateKey(
h_root, 0,
0 /* KeyBasicInformation */,
buf.as_mut_ptr() as *mut _, buf.len() as u32, &mut len);
if s != 0 { break; }
let bi = &*(buf.as_ptr() as *const KEY_BASIC_INFORMATION);
// open subkey here, recurse, then delete the leaf
}
NtDeleteKey(h_root);
}Mappings MITRE ATT&CK
Last verified: 2026-05-20