NtRenameKey
Renames an existing registry key in place — no Win32 wrapper, callable only via the NT API.
Prototype
NTSTATUS NtRenameKey( HANDLE KeyHandle, PUNICODE_STRING NewName );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| KeyHandle | HANDLE | in | Handle to the key to rename, opened with KEY_WRITE access. |
| NewName | PUNICODE_STRING | in | New leaf name (not a path). Must not contain a backslash and must be unique among siblings. |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x158 | win10-1507 |
| Win10 1607 | 0x15F | win10-1607 |
| Win10 1703 | 0x165 | win10-1703 |
| Win10 1709 | 0x168 | win10-1709 |
| Win10 1803 | 0x16A | win10-1803 |
| Win10 1809 | 0x16B | win10-1809 |
| Win10 1903 | 0x16C | win10-1903 |
| Win10 1909 | 0x16C | win10-1909 |
| Win10 2004 | 0x172 | win10-2004 |
| Win10 20H2 | 0x172 | win10-20h2 |
| Win10 21H1 | 0x172 | win10-21h1 |
| Win10 21H2 | 0x174 | win10-21h2 |
| Win10 22H2 | 0x174 | win10-22h2 |
| Win11 21H2 | 0x17C | win11-21h2 |
| Win11 22H2 | 0x17F | win11-22h2 |
| Win11 23H2 | 0x17F | win11-23h2 |
| Win11 24H2 | 0x181 | win11-24h2 |
| Server 2016 | 0x15F | winserver-2016 |
| Server 2019 | 0x16B | winserver-2019 |
| Server 2022 | 0x17A | winserver-2022 |
| Server 2025 | 0x181 | winserver-2025 |
Kernel module
Related APIs
Syscall stub
4C 8B D1 mov r10, rcx B8 81 01 00 00 mov eax, 0x181 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
NtRenameKey is undocumented in MSDN — Win32 exposes no equivalent and Reflection.RegistryKey can't reach it. The operation is performed atomically inside CmRenameKey, which calls CmpDuplicateKeyValueInformation onto a freshly-created KCB and then unlinks the old name from the parent's HHIVE. Locks held: HiveLock + KCB lock on parent. Returns STATUS_OBJECT_NAME_COLLISION if a sibling with NewName already exists.
Common malware usage
Rare in offense. The plausible niche is *allowlist evasion*: persistence schemes that rotate the name of a `Run` value (or the name of a key under `Image File Execution Options`) to defeat naive defender allowlists that look for specific key names. It can also be used to temporarily rename a security-related key while another change is staged, then rename back — though that pattern is more cleanly done with NtSaveKey/NtRestoreKey. Honest signal: most actual public reports of registry-rotation use NtSetValueKey to change a value name rather than NtRenameKey on the key itself.
Detection opportunities
Genuinely low background noise — almost nothing legitimate calls NtRenameKey. ETW Microsoft-Windows-Kernel-Registry emits a RenameKey task event. Sysmon Event 12 (RegistryEvent CreateKey/DeleteKey) does not split out renames cleanly — it surfaces as a DeleteKey on the old path followed by a CreateKey on the new path with the same KCB. CmRegisterCallbackEx delivers RegNtPreRenameKey / RegNtPostRenameKey which is the cleanest hook point. A single RenameKey under HKLM\SYSTEM\CurrentControlSet\Services or HKLM\Software\Microsoft\Windows\CurrentVersion\Run should always be investigated.
Direct syscall examples
cRotate a Run subkey name
// Rotate the leaf name of HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Updater
// to evade trivial 'name == Updater' allowlists.
UNICODE_STRING newName;
RtlInitUnicodeString(&newName, L"WindowsUpdateHelper");
NTSTATUS st = NtRenameKey(hRunSubkey, &newName);
if (st == STATUS_OBJECT_NAME_COLLISION) {
// sibling exists — pick a different rotated name
}asmx64 direct stub (Win11 24H2 SSN 0x181)
NtRenameKey PROC
mov r10, rcx
mov eax, 181h
syscall
ret
NtRenameKey ENDPrustntapi binding
// Cargo: ntapi = "0.4", widestring = "1"
let name = U16CString::from_str("WindowsUpdateHelper")?;
let mut us = UNICODE_STRING {
Length: (name.len() * 2) as u16,
MaximumLength: ((name.len() + 1) * 2) as u16,
Buffer: name.as_ptr() as _,
};
let status = unsafe { NtRenameKey(h_key, &mut us) };MITRE ATT&CK mappings
Last verified: 2026-05-20