NtRestoreKey
Overwrites a registry key's contents from a hive file — replaces subtrees in bulk.
Prototype
NTSTATUS NtRestoreKey( HANDLE KeyHandle, HANDLE FileHandle, ULONG Flags );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| KeyHandle | HANDLE | in | Open handle to the registry key whose contents will be replaced (must have KEY_WRITE). |
| FileHandle | HANDLE | in | Open handle to the hive file containing the source contents (opened with GENERIC_READ). |
| Flags | ULONG | in | REG_WHOLE_HIVE_VOLATILE (4), REG_REFRESH_HIVE (2), REG_NO_LAZY_FLUSH (4), REG_FORCE_RESTORE (8). |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x160 | win10-1507 |
| Win10 1607 | 0x167 | win10-1607 |
| Win10 1703 | 0x16D | win10-1703 |
| Win10 1709 | 0x170 | win10-1709 |
| Win10 1803 | 0x172 | win10-1803 |
| Win10 1809 | 0x173 | win10-1809 |
| Win10 1903 | 0x174 | win10-1903 |
| Win10 1909 | 0x174 | win10-1909 |
| Win10 2004 | 0x17A | win10-2004 |
| Win10 20H2 | 0x17A | win10-20h2 |
| Win10 21H1 | 0x17A | win10-21h1 |
| Win10 21H2 | 0x17C | win10-21h2 |
| Win10 22H2 | 0x17C | win10-22h2 |
| Win11 21H2 | 0x184 | win11-21h2 |
| Win11 22H2 | 0x187 | win11-22h2 |
| Win11 23H2 | 0x187 | win11-23h2 |
| Win11 24H2 | 0x189 | win11-24h2 |
| Server 2016 | 0x167 | winserver-2016 |
| Server 2019 | 0x173 | winserver-2019 |
| Server 2022 | 0x182 | winserver-2022 |
| Server 2025 | 0x189 | winserver-2025 |
Kernel module
Related APIs
Syscall stub
4C 8B D1 mov r10, rcx B8 89 01 00 00 mov eax, 0x189 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
NtRestoreKey is the inverse of NtSaveKey: it replaces the contents of an open key with whatever is contained in a hive file. With `REG_FORCE_RESTORE` the kernel does so even when there are open handles to the destination subtree. The caller needs **SeRestorePrivilege**. The Win32 wrapper is `RegRestoreKeyW`. The operation is atomic at the hive-block level; partial failure leaves the destination in the pre-restore state.
Common malware usage
Two patterns dominate. First, **tampering with persistence**: an attacker who staged a known-good Run-key template can overwrite `HKLM\Software\Microsoft\Windows\CurrentVersion\Run` (or a service config subtree) wholesale, replacing every entry in one syscall — useful for both planting persistence *and* erasing competing entries from rival malware. Second, **rollback after tampering**: red-team tooling sometimes takes a NtSaveKey snapshot, modifies a key, performs work, and then NtRestoreKey-rolls back to defeat host-based change auditing. Less commonly, ransomware uses it to swap out service-DLL paths in bulk before reboot.
Detection opportunities
ETW `Microsoft-Windows-Kernel-Registry` emits a load/restore event distinct from value-set events. Sysmon Event 13 fires per value modified by the restore — a single NtRestoreKey can produce a *burst* of Event 13 records with identical timestamps under the same key, which is itself an unusual pattern worth a rule. SeRestorePrivilege enablement (Sysmon 4673) immediately preceding a registry write is a strong leading indicator. Hunting tip: alert on REG_FORCE_RESTORE flag usage — it is almost never seen in benign software.
Direct syscall examples
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtRestoreKey (SSN 0x189 on Win11 24H2 — drifts per build)
NtRestoreKey PROC
mov r10, rcx ; KeyHandle
mov eax, 189h ; SSN
syscall
ret
NtRestoreKey ENDPcBulk-rewrite Run keys from staged template
// Overwrite HKLM\...\Run wholesale from a prepared hive file — useful for both
// persistence install and rival-eviction. Requires SeRestorePrivilege.
#include <windows.h>
LONG RestoreRunKey(LPCWSTR hivePath) {
HKEY hRun = NULL;
LONG s = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
0, KEY_ALL_ACCESS, &hRun);
if (s != ERROR_SUCCESS) return s;
// REG_FORCE_RESTORE (8) replaces even with open handles elsewhere.
s = RegRestoreKeyW(hRun, hivePath, 8 /* REG_FORCE_RESTORE */);
RegCloseKey(hRun);
return s;
}cDirect NtRestoreKey call
// Snap a key handle and a hive file handle, then restore atomically.
#include <windows.h>
#include <winternl.h>
typedef NTSTATUS (NTAPI *pNtRestoreKey)(HANDLE, HANDLE, ULONG);
NTSTATUS DoRestore(HANDLE hKey, HANDLE hFile, ULONG flags) {
pNtRestoreKey fn = (pNtRestoreKey)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtRestoreKey");
return fn(hKey, hFile, flags);
}MITRE ATT&CK mappings
Last verified: 2026-05-20