> Windows Syscalls
ntoskrnl.exeT1003.002T1574T1106

NtLoadKeyEx

Modern hive-load syscall — backs RegLoadKeyW, RegLoadAppKeyW and the AppContainer registry virtualization layer.

Prototype

NTSTATUS NtLoadKeyEx(
  POBJECT_ATTRIBUTES TargetKey,
  POBJECT_ATTRIBUTES SourceFile,
  ULONG              Flags,
  HANDLE             TrustClassKey,
  HANDLE             Event,
  ACCESS_MASK        DesiredAccess,
  PHANDLE            RootHandle,
  PIO_STATUS_BLOCK   IoStatusBlock
);

Arguments

NameTypeDirDescription
TargetKeyPOBJECT_ATTRIBUTESinMount-point object attributes; for REG_APP_HIVE this is a private namespace not visible to other processes.
SourceFilePOBJECT_ATTRIBUTESinOn-disk hive file (NT path). Must be on a local volume; remote paths are rejected.
FlagsULONGinREG_NO_LAZY_FLUSH (0x4), REG_APP_HIVE (0x10), REG_PROCESS_PRIVATE (0x20), REG_HIVE_NO_RM (0x100), REG_HIVE_SINGLE_LOG (0x200), REG_BOOT_HIVE (0x400), REG_LOAD_HIVE_OPEN_HANDLE (0x800), REG_FLUSH_HIVE_FILE_GROWTH (0x1000), REG_OPEN_READ_ONLY (0x2000), REG_IMMUTABLE (0x4000), REG_NO_IMPERSONATION_FALLBACK (0x8000), REG_APP_HIVE_OPEN_READ_ONLY (0x10000).
TrustClassKeyHANDLEinOptional handle to a trusted hive used to authenticate the new hive's class GUID; typically NULL.
EventHANDLEinOptional event signalled when the hive is recovered from a log file; usually NULL.
DesiredAccessACCESS_MASKinAccess mask requested on the returned root handle when REG_LOAD_HIVE_OPEN_HANDLE is set; otherwise 0.
RootHandlePHANDLEoutReceives a handle to the loaded hive's root key when REG_LOAD_HIVE_OPEN_HANDLE is set (this is how RegLoadAppKeyW returns an HKEY).
IoStatusBlockPIO_STATUS_BLOCKoutReceives the final NTSTATUS and information word from the I/O subsystem (recovered, fresh, etc.).

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070xF8win10-1507
Win10 16070xFDwin10-1607
Win10 17030x101win10-1703
Win10 17090x102win10-1709
Win10 18030x103win10-1803
Win10 18090x103win10-1809
Win10 19030x104win10-1903
Win10 19090x104win10-1909
Win10 20040x109win10-2004
Win10 20H20x109win10-20h2
Win10 21H10x109win10-21h1
Win10 21H20x10Awin10-21h2
Win10 22H20x10Awin10-22h2
Win11 21H20x110win11-21h2
Win11 22H20x111win11-22h2
Win11 23H20x111win11-23h2
Win11 24H20x113win11-24h2
Server 20160xFDwinserver-2016
Server 20190x103winserver-2019
Server 20220x10Fwinserver-2022
Server 20250x113winserver-2025

Kernel module

ntoskrnl.exeNtLoadKeyEx

Related APIs

RegLoadKeyWRegLoadAppKeyWRegUnLoadKeyWNtLoadKeyNtLoadKey2NtLoadKey3NtUnloadKey2

Syscall stub

4C 8B D1            mov r10, rcx
B8 13 01 00 00      mov eax, 0x113
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

`NtLoadKeyEx` is the canonical modern hive-load primitive. Two Win32 APIs sit on top of it: `RegLoadKeyW` (classic admin mount of a hive under HKLM / HKU, requires `SeRestorePrivilege`) and the much more interesting `RegLoadAppKeyW` (per-process, per-file private hive, **no privileges required** — works from a Low-IL AppContainer). The `REG_APP_HIVE | REG_PROCESS_PRIVATE | REG_LOAD_HIVE_OPEN_HANDLE` flag combination drives the AppContainer / Centennial registry virtualization layer; UWP packages each get a private hive at `\Registry\WC\<package>` that no other process can see. Kernel handler is `CmLoadKey` (`ntoskrnl.exe`), gated by `CmpCheckLoadHiveAccess`.

Common malware usage

Two distinct abuse paths. (1) **Admin / post-exploitation**: same SAM/SYSTEM/SECURITY offline parsing as `NtLoadKey` — operators copy the hive via VSS or `reg save HKLM\SAM`, then mount it under HKU with `NtLoadKeyEx`. (2) **AppContainer-aware loaders**: malware running inside a sandboxed UWP / Edge renderer / MSIX context can use `REG_APP_HIVE` to instantiate a private hive backed by a writable file under its package data directory — useful as a staging or config-stash that survives reboot without touching HKCU and without tripping `RegSetValueEx` on monitored keys. Phantom-DLL-Hollowing-style loaders also use `REG_APP_HIVE | REG_OPEN_READ_ONLY` to mount a hive whose backing file is a payload-stuffed `.dat` blob.

Detection opportunities

Same blue-team posture as `NtLoadKey`/`NtLoadKey2`: `Microsoft-Windows-Kernel-Registry` ETW event ID 9 (HiveLoaded) is the authoritative source. The high-quality signal is the path of the *backing file* — `RegLoadAppKeyW` legitimately loads files under `C:\Users\<u>\AppData\Local\Packages\<pkg>\Settings\settings.dat`, anything else (especially a hive file under `C:\Windows\Temp`, `\ProgramData\`, or a downloaded blob) is anomalous. Pair with Sysmon Event ID 11 (FileCreate) on `*.dat`/`*.hve` writes in suspicious directories and Event ID 1 (Process Create) showing `SeRestorePrivilege` enablement for full-tree mounts.

Direct syscall examples

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtLoadKeyEx (SSN 0x113 on Win11 24H2)
NtLoadKeyEx PROC
    mov  r10, rcx          ; TargetKey
    mov  eax, 113h         ; SSN — drifts per build
    syscall
    ret
NtLoadKeyEx ENDP

cAppContainer-style private hive (no privileges required)

// Replicates what RegLoadAppKeyW does internally. Works from Low-IL AppContainers.
#include <windows.h>
#include <winternl.h>

#define REG_APP_HIVE                0x00000010
#define REG_PROCESS_PRIVATE         0x00000020
#define REG_LOAD_HIVE_OPEN_HANDLE   0x00000800

typedef NTSTATUS (NTAPI *pNtLoadKeyEx)(
    POBJECT_ATTRIBUTES, POBJECT_ATTRIBUTES, ULONG,
    HANDLE, HANDLE, ACCESS_MASK, PHANDLE, PIO_STATUS_BLOCK);

HANDLE LoadPrivateHive(LPCWSTR ntHiveFile) {
    HANDLE hRoot = NULL;
    IO_STATUS_BLOCK iosb = {0};
    UNICODE_STRING uMount, uFile;
    OBJECT_ATTRIBUTES oaMount, oaFile;
    // Mount path is irrelevant under REG_APP_HIVE | REG_PROCESS_PRIVATE
    RtlInitUnicodeString(&uMount, L"\\REGISTRY\\A\\{00000000-0000-0000-0000-000000000000}");
    RtlInitUnicodeString(&uFile,  ntHiveFile);
    InitializeObjectAttributes(&oaMount, &uMount, OBJ_CASE_INSENSITIVE, NULL, NULL);
    InitializeObjectAttributes(&oaFile,  &uFile,  OBJ_CASE_INSENSITIVE, NULL, NULL);
    pNtLoadKeyEx fn = (pNtLoadKeyEx)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtLoadKeyEx");
    fn(&oaMount, &oaFile,
       REG_APP_HIVE | REG_PROCESS_PRIVATE | REG_LOAD_HIVE_OPEN_HANDLE,
       NULL, NULL, KEY_ALL_ACCESS, &hRoot, &iosb);
    return hRoot;  // HKEY-equivalent, usable with NtOpenKey / NtSetValueKey
}

rustwindows-sys: classic admin-mount of an offline SYSTEM hive

// Cargo: windows-sys = { version = "0.59", features = [
//   "Win32_Foundation", "Win32_System_Registry", "Win32_Security" ] }
use windows_sys::Win32::System::Registry::{RegLoadKeyW, HKEY_LOCAL_MACHINE};
use windows_sys::core::PCWSTR;

fn mount_offline_system(hive_path_utf16: &[u16], subkey_utf16: &[u16]) -> i32 {
    // RegLoadKeyW → NtLoadKeyEx with Flags=0, TrustClassKey=NULL,
    // no REG_LOAD_HIVE_OPEN_HANDLE. Requires SeRestorePrivilege+SeBackupPrivilege.
    unsafe {
        RegLoadKeyW(HKEY_LOCAL_MACHINE,
                    subkey_utf16.as_ptr() as PCWSTR,
                    hive_path_utf16.as_ptr() as PCWSTR) as i32
    }
}

MITRE ATT&CK mappings

Last verified: 2026-05-20