> Windows Syscalls
ntoskrnl.exeT1112T1070.001T1070.009

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

NameTypeDirDescription
KeyHandleHANDLEinHandle précédemment ouvert avec le droit d'accès DELETE (ou KEY_ALL_ACCESS).

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 15070xC5win10-1507
Win10 16070xC8win10-1607
Win10 17030xCBwin10-1703
Win10 17090xCCwin10-1709
Win10 18030xCDwin10-1803
Win10 18090xCEwin10-1809
Win10 19030xCFwin10-1903
Win10 19090xCFwin10-1909
Win10 20040xD3win10-2004
Win10 20H20xD3win10-20h2
Win10 21H10xD3win10-21h1
Win10 21H20xD4win10-21h2
Win10 22H20xD4win10-22h2
Win11 21H20xD9win11-21h2
Win11 22H20xDAwin11-22h2
Win11 23H20xDAwin11-23h2
Win11 24H20xDCwin11-24h2
Server 20160xC8winserver-2016
Server 20190xCEwinserver-2019
Server 20220xD8winserver-2022
Server 20250xDCwinserver-2025

Module noyau

ntoskrnl.exeNtDeleteKey

APIs liées

RegDeleteKeyWRegDeleteKeyExWRegDeleteTreeWNtDeleteValueKeyNtEnumerateKeyNtClose

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 ENDP

rustDepth-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