> Windows Syscalls
ntoskrnl.exeT1003.002T1574T1106

NtLoadKeyEx

Syscall moderne de chargement de ruche — sous-tend RegLoadKeyW, RegLoadAppKeyW et la virtualisation registre des AppContainers.

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_ATTRIBUTESinAttributs d'objet du point de montage ; pour REG_APP_HIVE c'est un namespace privé invisible aux autres processus.
SourceFilePOBJECT_ATTRIBUTESinFichier de ruche sur disque (chemin NT). Doit être sur un volume local ; les chemins distants sont rejetés.
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).
TrustClassKeyHANDLEinHandle optionnel vers une ruche de confiance pour authentifier le GUID de classe de la nouvelle ruche ; typiquement NULL.
EventHANDLEinÉvénement optionnel signalé quand la ruche est restaurée depuis un fichier de journal ; généralement NULL.
DesiredAccessACCESS_MASKinMasque d'accès demandé sur le handle racine retourné quand REG_LOAD_HIVE_OPEN_HANDLE est défini ; sinon 0.
RootHandlePHANDLEoutReçoit un handle sur la clé racine de la ruche chargée quand REG_LOAD_HIVE_OPEN_HANDLE est défini (ainsi RegLoadAppKeyW renvoie un HKEY).
IoStatusBlockPIO_STATUS_BLOCKoutReçoit le NTSTATUS final et le mot d'information du sous-système I/O (récupéré, neuf, etc.).

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
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

Module noyau

ntoskrnl.exeNtLoadKeyEx

APIs liées

RegLoadKeyWRegLoadAppKeyWRegUnLoadKeyWNtLoadKeyNtLoadKey2NtLoadKey3NtUnloadKey2

Stub du syscall

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

Notes non documentées

`NtLoadKeyEx` est la primitive moderne canonique de chargement de ruche. Deux APIs Win32 s'appuient dessus : `RegLoadKeyW` (montage admin classique sous HKLM / HKU, nécessite `SeRestorePrivilege`) et le bien plus intéressant `RegLoadAppKeyW` (ruche privée par processus / par fichier, **sans privilège requis** — fonctionne depuis un AppContainer en intégrité basse). La combinaison `REG_APP_HIVE | REG_PROCESS_PRIVATE | REG_LOAD_HIVE_OPEN_HANDLE` pilote la couche de virtualisation registre AppContainer / Centennial ; chaque package UWP reçoit une ruche privée sous `\Registry\WC\<package>` invisible aux autres processus. Le handler noyau est `CmLoadKey` (`ntoskrnl.exe`), gardé par `CmpCheckLoadHiveAccess`.

Usage courant par les malwares

Deux voies d'abus distinctes. (1) **Admin / post-exploitation** : même parsing offline SAM/SYSTEM/SECURITY que `NtLoadKey` — l'opérateur copie la ruche via VSS ou `reg save HKLM\SAM`, puis la monte sous HKU avec `NtLoadKeyEx`. (2) **Loaders AppContainer-aware** : un malware tournant dans un UWP sandboxé / un renderer Edge / un contexte MSIX peut utiliser `REG_APP_HIVE` pour instancier une ruche privée adossée à un fichier écrivable sous son répertoire de données de package — utile comme cache de staging ou de configuration survivant au reboot sans toucher HKCU ni déclencher `RegSetValueEx` sur des clés surveillées. Des loaders style Phantom DLL Hollowing utilisent aussi `REG_APP_HIVE | REG_OPEN_READ_ONLY` pour monter une ruche dont le fichier source est un blob `.dat` chargé de payload.

Opportunités de détection

Posture blue-team identique à `NtLoadKey`/`NtLoadKey2` : l'événement ETW `Microsoft-Windows-Kernel-Registry` ID 9 (HiveLoaded) est la source faisant autorité. Le signal de qualité est le chemin du *fichier source* — `RegLoadAppKeyW` charge légitimement des fichiers sous `C:\Users\<u>\AppData\Local\Packages\<pkg>\Settings\settings.dat`, tout le reste (en particulier ruche sous `C:\Windows\Temp`, `\ProgramData\` ou blob téléchargé) est anormal. À coupler avec Sysmon Event ID 11 (FileCreate) sur des écritures `*.dat`/`*.hve` dans des répertoires suspects et Event ID 1 (Process Create) montrant l'activation de `SeRestorePrivilege` pour les montages d'arbre complet.

Exemples de syscalls directs

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
    }
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20