NtUnloadKey
Hängt einen zuvor geladenen Registry-Hive vom Konfigurationsmanager ab.
Prototyp
NTSTATUS NtUnloadKey( POBJECT_ATTRIBUTES TargetKey );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| TargetKey | POBJECT_ATTRIBUTES | in | Objekt-Attribute, die den Wurzelschlüssel des zu entladenden Hives benennen, z. B. \Registry\User\TempHive. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x1AA | win10-1507 |
| Win10 1607 | 0x1B3 | win10-1607 |
| Win10 1703 | 0x1B9 | win10-1703 |
| Win10 1709 | 0x1BD | win10-1709 |
| Win10 1803 | 0x1BF | win10-1803 |
| Win10 1809 | 0x1C0 | win10-1809 |
| Win10 1903 | 0x1C1 | win10-1903 |
| Win10 1909 | 0x1C1 | win10-1909 |
| Win10 2004 | 0x1C7 | win10-2004 |
| Win10 20H2 | 0x1C7 | win10-20h2 |
| Win10 21H1 | 0x1C7 | win10-21h1 |
| Win10 21H2 | 0x1C9 | win10-21h2 |
| Win10 22H2 | 0x1C9 | win10-22h2 |
| Win11 21H2 | 0x1D3 | win11-21h2 |
| Win11 22H2 | 0x1D7 | win11-22h2 |
| Win11 23H2 | 0x1D7 | win11-23h2 |
| Win11 24H2 | 0x1DA | win11-24h2 |
| Server 2016 | 0x1B3 | winserver-2016 |
| Server 2019 | 0x1C0 | winserver-2019 |
| Server 2022 | 0x1CF | winserver-2022 |
| Server 2025 | 0x1DA | winserver-2025 |
Kernel-Modul
Verwandte APIs
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.
Erkennungsmö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 ENDPcOffline 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