NtSetValueKey
Escribe un valor nombrado en una clave de registro abierta — pilar de las persistencias Run y IFEO.
Prototipo
NTSTATUS NtSetValueKey( HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| KeyHandle | HANDLE | in | Handle a una clave abierta vía NtOpenKey/NtCreateKey con acceso KEY_SET_VALUE. |
| ValueName | PUNICODE_STRING | in | Nombre del valor a establecer. NULL o cadena vacía apunta al valor predeterminado. |
| TitleIndex | ULONG | in | Reservado. Debe ser cero. |
| Type | ULONG | in | Tipo de valor: REG_SZ, REG_EXPAND_SZ, REG_DWORD, REG_BINARY, REG_MULTI_SZ, etc. |
| Data | PVOID | in | Puntero al búfer de datos a escribir. |
| DataSize | ULONG | in | Tamaño del búfer en bytes (incluir el NUL final para REG_SZ). |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x60 | win10-1507 |
| Win10 1607 | 0x60 | win10-1607 |
| Win10 1703 | 0x60 | win10-1703 |
| Win10 1709 | 0x60 | win10-1709 |
| Win10 1803 | 0x60 | win10-1803 |
| Win10 1809 | 0x60 | win10-1809 |
| Win10 1903 | 0x60 | win10-1903 |
| Win10 1909 | 0x60 | win10-1909 |
| Win10 2004 | 0x60 | win10-2004 |
| Win10 20H2 | 0x60 | win10-20h2 |
| Win10 21H1 | 0x60 | win10-21h1 |
| Win10 21H2 | 0x60 | win10-21h2 |
| Win10 22H2 | 0x60 | win10-22h2 |
| Win11 21H2 | 0x60 | win11-21h2 |
| Win11 22H2 | 0x60 | win11-22h2 |
| Win11 23H2 | 0x60 | win11-23h2 |
| Win11 24H2 | 0x60 | win11-24h2 |
| Server 2016 | 0x60 | winserver-2016 |
| Server 2019 | 0x60 | winserver-2019 |
| Server 2022 | 0x60 | winserver-2022 |
| Server 2025 | 0x60 | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 60 00 00 00 mov eax, 0x60 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
Estable en `0x60` desde Windows 7 hasta Win11 24H2. Combinar con NtCreateKey/NtOpenKey para escribir valores sin pasar por advapi32, donde residen la mayoría de hooks de usuario de los EDR. El kernel encamina la llamada vía CmSetValueKey → CmpSetValueKeyNew/Existing; los flush del hive son diferidos (CmpLazyFlushHiveList), de modo que un valor recién escrito puede no llegar a disco hasta varios segundos después — útil para actores que corren contra la detección.
Uso común por malware
El lado de ejecución de la persistencia en registro. Una vez abierta una subclave de autostart, NtSetValueKey escribe el comando de lanzamiento: - `Run` / `RunOnce`: un REG_SZ apuntando al implante. - `Image File Execution Options\<víctima.exe>` → `Debugger` REG_SZ → binario atacante (T1546.012). - `Winlogon\Userinit` / `Winlogon\Shell` extendidos con el payload. - `Services\<nombre>\ImagePath` para secuestro de servicio. - `AppInit_DLLs` para inyectarse en todo proceso que enlace user32.dll. Los llamadores por syscall directa también lo usan para alterar valores de seguridad (DisableAntiSpyware, AntiSpywareEnabled, SubmitSamplesConsent) si están elevados.
Oportunidades de detección
ETW Microsoft-Windows-Kernel-Registry emite `EventSetValueKey` (Opcode 11) con la ruta de clave, nombre de valor, tipo y longitud — esencial para alertas de alta fidelidad sobre escrituras autostart e IFEO. Sysmon Event ID 13 (RegistryEvent: Set value) y Event ID 14 (Key/Value rename) cubren endpoints sin EDR. Alertas prioritarias: cualquier escritura bajo `*\CurrentVersion\Run*`, `*\Image File Execution Options\*\Debugger`, `*\Winlogon\(Userinit|Shell|AppInit_DLLs)`, y cualquier cambio en exclusiones de Defender o `SubmitSamplesConsent`. Correlacione con telemetría de carga de imágenes para capturar el proceso resultante en el siguiente inicio de sesión.
Ejemplos de syscalls directos
cWrite a Run-key persistence entry
// Drop HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Updater = C:\PD\impl.exe
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"Updater");
WCHAR data[] = L"C:\\ProgramData\\impl.exe";
NTSTATUS s = NtSetValueKey(
hRunKey, // from NtCreateKey/NtOpenKey
&name,
0, // TitleIndex
REG_SZ,
data,
(ULONG)((wcslen(data) + 1) * sizeof(WCHAR)));asmDirect stub (SSN 0x60)
NtSetValueKey PROC
mov r10, rcx
mov eax, 60h
syscall
ret
NtSetValueKey ENDPcIFEO Debugger hijack (T1546.012)
// HKLM\Software\Microsoft\Windows NT\CurrentVersion\
// Image File Execution Options\osk.exe!Debugger = cmd.exe
// Triggers when On-Screen Keyboard is launched (incl. Sticky Keys at logon).
UNICODE_STRING debuggerName;
RtlInitUnicodeString(&debuggerName, L"Debugger");
WCHAR debugger[] = L"C:\\Windows\\System32\\cmd.exe";
NtSetValueKey(hIfeoOskKey, &debuggerName, 0, REG_SZ,
debugger,
(ULONG)((wcslen(debugger) + 1) * sizeof(WCHAR)));Mapeos MITRE ATT&CK
Last verified: 2026-05-20