NtFlushKey
Fuerza la escritura en disco de todos los cambios pendientes de una clave de registro.
Prototipo
NTSTATUS NtFlushKey( HANDLE KeyHandle );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| KeyHandle | HANDLE | in | Handle abierto a cualquier clave del hive a flushear; se commitea todo el hive que contiene la clave. |
IDs de syscalls por versión de Windows
| Versión 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 |
Módulo del kernel
APIs relacionadas
Stub del 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
Notas no documentadas
NtFlushKey commitea todos los cambios en memoria para el *hive* que contiene la clave proporcionada a su archivo de disco. A pesar de la firma por clave, el kernel flushea todo el hive — el configuration manager no mantiene dirty bits por clave a la granularidad del flush. Diferencia con `NtFlushBuffersFile`: ese apunta a un archivo vía FILE_OBJECT, NtFlushKey apunta a un hive vía un handle de clave. El wrapper Win32 es `RegFlushKey`. El lazy flusher normalmente escribe hives sucios cada cinco segundos (`CmpLazyFlushIntervalInSeconds`); NtFlushKey fuerza la escritura inmediata.
Uso común por malware
El patrón principal de abuso es **anti-forense alrededor de la persistencia**: tras escribir una Run key, configuración de tarea programada, entrada de servicio o valor de COM-hijack, el malware llama a NtFlushKey para garantizar que el cambio se persista en disco *antes* del próximo reboot no limpio — relevante cuando la ventana del lazy-flush es mayor que la ventana de oportunidad esperada (exploit que dispara BSOD, hard reset planeado, ransomware que mata el host). Patrón secundario: algunos droppers flushean una entrada autorun recién escrita y luego borran inmediatamente el binario referenciado en disco, dejando metadatos Run-key apuntando a contenido que puede o no existir en el boot — pequeño estorbo anti-análisis.
Oportunidades de detección
Por sí solo, NtFlushKey no es interesante — explorer.exe y muchos drivers lo llaman rutinariamente. La señal útil es la *secuencia*: Sysmon Event 13 (set de valor de registro) en una clave de persistencia conocida, inmediatamente seguido de un flush desde el mismo PID, especialmente si ese PID está sin firmar o recién creado. ETW `Microsoft-Windows-Kernel-Registry` expone eventos flush con ruta de clave y PID. Correlacionar con Sysmon Event 11 (create / delete de archivo) sobre el binario referenciado por la entrada de persistencia.
Ejemplos de syscalls directos
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)
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20