NtFlushKey
Force l'écriture sur disque de toutes les modifications en attente d'une clé de registre.
Prototype
NTSTATUS NtFlushKey( HANDLE KeyHandle );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| KeyHandle | HANDLE | in | Handle ouvert vers une clé quelconque de la ruche à flusher ; toute la ruche contenant la clé est commitée. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0xDA | win10-1507 |
| Win10 1607 | 0xDD | win10-1607 |
| Win10 1703 | 0xE0 | win10-1703 |
| Win10 1709 | 0xE1 | win10-1709 |
| Win10 1803 | 0xE2 | win10-1803 |
| Win10 1809 | 0xE3 | win10-1809 |
| Win10 1903 | 0xE4 | win10-1903 |
| Win10 1909 | 0xE4 | win10-1909 |
| Win10 2004 | 0xE9 | win10-2004 |
| Win10 20H2 | 0xE9 | win10-20h2 |
| Win10 21H1 | 0xE9 | win10-21h1 |
| Win10 21H2 | 0xEA | win10-21h2 |
| Win10 22H2 | 0xEA | win10-22h2 |
| Win11 21H2 | 0xEF | win11-21h2 |
| Win11 22H2 | 0xF0 | win11-22h2 |
| Win11 23H2 | 0xF0 | win11-23h2 |
| Win11 24H2 | 0xF2 | win11-24h2 |
| Server 2016 | 0xDD | winserver-2016 |
| Server 2019 | 0xE3 | winserver-2019 |
| Server 2022 | 0xEE | winserver-2022 |
| Server 2025 | 0xF2 | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 F2 00 00 00 mov eax, 0xF2 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
NtFlushKey commit toutes les modifications en mémoire pour la *ruche* contenant la clé fournie vers son fichier disque. Malgré la signature par clé, le noyau flushe toute la ruche — le configuration manager ne maintient pas de dirty bits par clé à la granularité du flush. Différence avec `NtFlushBuffersFile` : ce dernier cible un fichier via FILE_OBJECT, NtFlushKey cible une ruche via un handle de clé. Le wrapper Win32 est `RegFlushKey`. Le lazy flusher écrit normalement les ruches sales toutes les cinq secondes (`CmpLazyFlushIntervalInSeconds`) ; NtFlushKey force l'écriture immédiate.
Usage courant par les malwares
Le pattern d'abus principal est l'**anti-forensique autour de la persistance** : après écriture d'une Run key, config de tâche planifiée, entrée de service ou valeur de COM-hijack, le malware appelle NtFlushKey pour garantir que la modification est persistée sur disque *avant* le prochain reboot non propre — important quand la fenêtre de lazy-flush est plus large que la fenêtre d'opportunité attendue (exploit déclenchant un BSOD, hard reset planifié, ransomware tueur d'hôte). Pattern secondaire : certains droppers flushent une entrée autorun fraîchement écrite, puis suppriment immédiatement le binaire référencé sur disque, laissant les métadonnées Run-key pointer sur un contenu peut-être absent au boot — petite nuisance anti-analyse.
Opportunités de détection
Seul, NtFlushKey est sans intérêt — explorer.exe et de nombreux drivers l'appellent en routine. Le signal utile est la *séquence* : Sysmon Event 13 (set de valeur registre) sur une clé de persistance connue, immédiatement suivi d'un flush depuis le même PID, surtout si ce PID est non signé ou récemment créé. L'ETW `Microsoft-Windows-Kernel-Registry` expose les événements flush avec chemin de clé et PID. Corréler avec Sysmon Event 11 (create / delete de fichier) sur le binaire référencé par l'entrée de persistance.
Exemples de syscalls directs
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtFlushKey (SSN 0xF2 on Win11 24H2 — drifts per build)
NtFlushKey PROC
mov r10, rcx ; KeyHandle
mov eax, 0F2h ; SSN
syscall
ret
NtFlushKey ENDPcPersistence write-then-flush
// Write a Run key and immediately flush — defeats lazy-flush race on hard reboot.
#include <windows.h>
LONG PersistAndFlush(LPCWSTR name, LPCWSTR cmd) {
HKEY hRun = NULL;
LONG s = RegCreateKeyExW(HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
0, NULL, 0, KEY_SET_VALUE, NULL, &hRun, NULL);
if (s != ERROR_SUCCESS) return s;
s = RegSetValueExW(hRun, name, 0, REG_SZ,
(const BYTE*)cmd,
(DWORD)((wcslen(cmd) + 1) * sizeof(WCHAR)));
if (s == ERROR_SUCCESS) RegFlushKey(hRun); // ← NtFlushKey under the hood
RegCloseKey(hRun);
return s;
}rustDirect NtFlushKey
// Cargo: ntapi = "0.4"
use ntapi::ntregapi::NtFlushKey;
use winapi::shared::ntdef::{HANDLE, NTSTATUS};
unsafe fn flush(key: HANDLE) -> NTSTATUS {
NtFlushKey(key)
}Mappings MITRE ATT&CK
Last verified: 2026-05-20