> Windows Syscalls
ntoskrnl.exeT1003.002T1112T1070

NtUnloadKey

Hängt einen zuvor geladenen Registry-Hive vom Konfigurationsmanager ab.

Prototyp

NTSTATUS NtUnloadKey(
  POBJECT_ATTRIBUTES TargetKey
);

Argumente

NameTypeDirDescription
TargetKeyPOBJECT_ATTRIBUTESinObjekt-Attribute, die den Wurzelschlüssel des zu entladenden Hives benennen, z. B. \Registry\User\TempHive.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x1AAwin10-1507
Win10 16070x1B3win10-1607
Win10 17030x1B9win10-1703
Win10 17090x1BDwin10-1709
Win10 18030x1BFwin10-1803
Win10 18090x1C0win10-1809
Win10 19030x1C1win10-1903
Win10 19090x1C1win10-1909
Win10 20040x1C7win10-2004
Win10 20H20x1C7win10-20h2
Win10 21H10x1C7win10-21h1
Win10 21H20x1C9win10-21h2
Win10 22H20x1C9win10-22h2
Win11 21H20x1D3win11-21h2
Win11 22H20x1D7win11-22h2
Win11 23H20x1D7win11-23h2
Win11 24H20x1DAwin11-24h2
Server 20160x1B3winserver-2016
Server 20190x1C0winserver-2019
Server 20220x1CFwinserver-2022
Server 20250x1DAwinserver-2025

Kernel-Modul

ntoskrnl.exeNtUnloadKey

Verwandte APIs

RegUnLoadKeyWRegLoadKeyWNtLoadKeyNtLoadKey2NtUnloadKey2NtUnloadKeyEx

Syscall-Stub

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

Undokumentierte Hinweise

NtUnloadKey hängt einen zuvor über NtLoadKey / `reg load` angehängten Registry-Hive zwangsweise ab. Der Aufrufer muss SeRestorePrivilege besitzen, sonst schlägt der Aufruf mit STATUS_PRIVILEGE_NOT_HELD fehl. Intern läuft CmUnloadKey die CM_KEY_CONTROL_BLOCK-Kette ab und schreibt ausstehende Änderungen zurück, bevor der Hive abgebaut wird — ein nachlässiges Entladen eines noch genutzten Hives kann mit offenen Key-Handles anderer Threads kollidieren und STATUS_CANNOT_DELETE liefern. Die Variante NtUnloadKey2 akzeptiert ein `Flags`-Argument, um das Abhängen zu erzwingen.

Häufige Malware-Nutzung

Wird als Cleanup-Hälfte eines Offline-Hive-Missbrauchs verwendet: ein Operator führt `reg load HKU\Tmp C:\Users\opfer\NTUSER.DAT` aus, extrahiert Anmeldedaten / liest Run-Keys aus dem gemounteten Hive und ruft dann NtUnloadKey auf, um den Hive zu entfernen und den offensichtlichen Indikator zu löschen. Die gleiche Primitive dient als leichte Anti-Forensik — durch das Entladen eines Hives, den ein Triage-Tool gerade gemappt hat, kann der Implant die Sicht des Analysten unterbrechen. Einige Loader entladen auch temporär gemountete Hives, die zur AppCompat-/TypedURL-Manipulation dienten.

Erkennungs­möglichkeiten

Sysmon hat kein dediziertes Event für Hive-Unload, aber der ETW-Provider Microsoft-Windows-Kernel-Registry liefert Event ID 1 (HiveLoad) und Event ID 2 (HiveUnload) inklusive Hive-Pfad. Die Audit-Subkategorie "Registry" (4657 / 4660) deckt Hive-Load/Unload nicht ab; benötigt wird "Other System Events" oder direkt der Kernel-Registry-ETW-Provider. Defender ATP feuert eine hochwertige Warnung bei `reg unload` von Hives außerhalb von %SystemRoot%\System32\config — auffällig, wenn ein vorheriger Load gegen ein fremdes Benutzerprofil vorausging.

Direkte Syscall-Beispiele

asmx64 direct stub (Win11 24H2 SSN 0x1DA)

NtUnloadKey PROC
    mov  r10, rcx
    mov  eax, 1DAh
    syscall
    ret
NtUnloadKey ENDP

cOffline hive cleanup after credential harvest

// After mounting another user's NTUSER.DAT via NtLoadKey and harvesting,
// detach it so `reg query HKU` no longer reveals the staged hive.
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"\\Registry\\User\\TempHive");

OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);

NTSTATUS st = NtUnloadKey(&oa);
if (st == STATUS_CANNOT_DELETE) {
    // Some handle is still open; force via NtUnloadKey2 with REG_FORCE_UNLOAD.
}

rustwindows-sys + SeRestorePrivilege enablement

// Cargo: windows-sys = "0.59" (Win32_Security, Win32_System_Registry)
// Caller must first enable SeRestorePrivilege via NtAdjustPrivilegesToken.
unsafe {
    let mut name = make_unicode_string("\\Registry\\User\\TempHive");
    let mut oa = OBJECT_ATTRIBUTES {
        Length: size_of::<OBJECT_ATTRIBUTES>() as u32,
        ObjectName: &mut name,
        Attributes: OBJ_CASE_INSENSITIVE,
        ..zeroed()
    };
    let st = NtUnloadKey(&mut oa);
    assert!(st == 0, "NtUnloadKey failed: {st:#x}");
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20