> Windows Syscalls
ntoskrnl.exeT1547.001T1112T1106

NtFlushKey

Fuerza la escritura en disco de todos los cambios pendientes de una clave de registro.

Prototipo

NTSTATUS NtFlushKey(
  HANDLE  KeyHandle
);

Argumentos

NameTypeDirDescription
KeyHandleHANDLEinHandle 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 WindowsID de syscallBuild
Win10 15070xDAwin10-1507
Win10 16070xDDwin10-1607
Win10 17030xE0win10-1703
Win10 17090xE1win10-1709
Win10 18030xE2win10-1803
Win10 18090xE3win10-1809
Win10 19030xE4win10-1903
Win10 19090xE4win10-1909
Win10 20040xE9win10-2004
Win10 20H20xE9win10-20h2
Win10 21H10xE9win10-21h1
Win10 21H20xEAwin10-21h2
Win10 22H20xEAwin10-22h2
Win11 21H20xEFwin11-21h2
Win11 22H20xF0win11-22h2
Win11 23H20xF0win11-23h2
Win11 24H20xF2win11-24h2
Server 20160xDDwinserver-2016
Server 20190xE3winserver-2019
Server 20220xEEwinserver-2022
Server 20250xF2winserver-2025

Módulo del kernel

ntoskrnl.exeNtFlushKey

APIs relacionadas

RegFlushKeyNtFlushBuffersFileNtSaveKeyNtSetValueKey

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 ENDP

cPersistence 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