> Windows Syscalls
ntoskrnl.exeT1518T1012T1547.001

NtEnumerateKey

Enumera subclaves de una clave del registro — usado para recorrer AutoRun, IFEO y Services en busca de persistencia.

Prototipo

NTSTATUS NtEnumerateKey(
  HANDLE                KeyHandle,
  ULONG                 Index,
  KEY_INFORMATION_CLASS KeyInformationClass,
  PVOID                 KeyInformation,
  ULONG                 Length,
  PULONG                ResultLength
);

Argumentos

NameTypeDirDescription
KeyHandleHANDLEinHandle abierto con KEY_ENUMERATE_SUB_KEYS (parte de KEY_READ).
IndexULONGinÍndice 0-based de la subclave. Incrementar hasta STATUS_NO_MORE_ENTRIES.
KeyInformationClassKEY_INFORMATION_CLASSinFormato: KeyBasicInformation=0, KeyNodeInformation=1, KeyFullInformation=2, KeyNameInformation=3.
KeyInformationPVOIDoutBúfer de salida que recibe la estructura KEY_*_INFORMATION solicitada.
LengthULONGinTamaño de KeyInformation en bytes.
ResultLengthPULONGoutRecibe el tamaño requerido si el búfer es insuficiente.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070x32win10-1507
Win10 16070x32win10-1607
Win10 17030x32win10-1703
Win10 17090x32win10-1709
Win10 18030x32win10-1803
Win10 18090x32win10-1809
Win10 19030x32win10-1903
Win10 19090x32win10-1909
Win10 20040x32win10-2004
Win10 20H20x32win10-20h2
Win10 21H10x32win10-21h1
Win10 21H20x32win10-21h2
Win10 22H20x32win10-22h2
Win11 21H20x32win11-21h2
Win11 22H20x32win11-22h2
Win11 23H20x32win11-23h2
Win11 24H20x32win11-24h2
Server 20160x32winserver-2016
Server 20190x32winserver-2019
Server 20220x32winserver-2022
Server 20250x32winserver-2025

Módulo del kernel

ntoskrnl.exeNtEnumerateKey

APIs relacionadas

RegEnumKeyExWNtEnumerateValueKeyNtQueryKeyRegQueryInfoKeyWNtOpenKeyNtOpenKeyEx

Stub del syscall

4C 8B D1            mov r10, rcx
B8 32 00 00 00      mov eax, 0x32
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

Enumeración basada en índice: el invocador itera desde `Index=0` hasta `STATUS_NO_MORE_ENTRIES`. Añadir o eliminar una subclave durante la enumeración desplaza los índices — invocadores robustos reintentan el índice fallido o capturan una lista de nombres antes de procesar. SSN `0x32` estable desde Windows 7. `NtEnumerateKey` solo devuelve subclaves — para valores hace falta `NtEnumerateValueKey` (syscall hermano de la misma forma).

Uso común por malware

**Descubrimiento de persistencia (T1518 + T1012 + T1547.x)** — rojo y azul usan la misma primitiva en extremos opuestos de la kill chain. El uso ofensivo interesante es *enumeración de autorun antes de plantar*: recorrer cada clave de auto-ejecución estándar para encontrar un nombre libre (evitar colisiones) o descubrir entradas existentes que el implante pueda secuestrar (sustituir el binario de un lanzador de tarea programada instalado pero raramente activo en vez de crear una entrada que sería la única ausente de las baselines). Rutas canónicas: `\Registry\Machine\Software\Microsoft\Windows\CurrentVersion\Run`, `RunOnce`, `Explorer\Shell Folders`, `Image File Execution Options` (cuyas subclaves son *nombres de ejecutables* — enumerarlas encuentra oportunidades de hijack IFEO debugger), `App Paths`, `\Services` (drivers Type=1, servicios own-process Type=16), `\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify`. Los stealers también enumeran `\Software\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles` para descubrir los GUID de perfiles Wi-Fi antes de extraer los PSK vía `wlanapi`.

Oportunidades de detección

El volumen de `NtEnumerateKey` es enorme en un host normal (refresh GPO, motor ASR de Defender, cada expansión del namespace Explorer). No es señal primaria útil. Dos señales derivadas funcionan: (1) **enumeración de clave sensible por proceso fuera de baseline** — alertar cuando un proceso cuyo hash de imagen nunca enumeró `\Microsoft\Windows NT\CurrentVersion\Image File Execution Options` lo hace; (2) **enumeración seguida de SetValueKey** en el mismo padre — los implantes suelen enumerar para esquivar colisiones y luego escribir. ETW Microsoft-Windows-Kernel-Registry transporta ambos eventos con timestamps suficientemente finos para correlar. Los EDR que registran `CmRegisterCallbackEx` reciben notificaciones `RegNtPreEnumerateKey`/`RegNtPostEnumerateKey` independientemente del estado de los hooks de usuario. Consulta de caza: mismo PID emite ≥ 20 `NtEnumerateKey` bajo `\Microsoft\Windows\CurrentVersion\Run*` y un `NtSetValueKey` a un hermano en 2 s.

Ejemplos de syscalls directos

cWalk Image File Execution Options subkeys

// hIfeo = handle to \Registry\Machine\Software\Microsoft\
//                  Windows NT\CurrentVersion\Image File Execution Options
for (ULONG i = 0;; ++i) {
    BYTE  buf[0x200];
    ULONG got = 0;
    NTSTATUS s = NtEnumerateKey(
        hIfeo, i,
        KeyBasicInformation,
        buf, sizeof(buf), &got);
    if (s == STATUS_NO_MORE_ENTRIES) break;
    if (!NT_SUCCESS(s)) continue;
    PKEY_BASIC_INFORMATION ki = (PKEY_BASIC_INFORMATION)buf;
    // ki->Name is the image name targetable by IFEO Debugger hijack
}

asmDirect stub (SSN 0x32)

NtEnumerateKey PROC
    mov  r10, rcx
    mov  eax, 32h
    syscall
    ret
NtEnumerateKey ENDP

rustSnapshot subkey names to avoid index drift

use ntapi::ntregapi::{NtEnumerateKey, KEY_BASIC_INFORMATION};
use winapi::shared::ntdef::HANDLE;

pub unsafe fn list_subkeys(h: HANDLE) -> Vec<String> {
    let mut names = Vec::new();
    let mut buf = vec![0u8; 0x400];
    for i in 0u32.. {
        let mut got = 0u32;
        let s = NtEnumerateKey(
            h, i, 0 /* KeyBasicInformation */,
            buf.as_mut_ptr() as *mut _, buf.len() as u32, &mut got);
        if s == 0x8000001A /* STATUS_NO_MORE_ENTRIES */ { break; }
        if s != 0 { continue; }
        let ki = &*(buf.as_ptr() as *const KEY_BASIC_INFORMATION);
        let name = core::slice::from_raw_parts(
            ki.Name.as_ptr(), (ki.NameLength / 2) as usize);
        names.push(String::from_utf16_lossy(name));
    }
    names
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20