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

NtDuplicateObject

Duplique un handle d'un processus source vers un processus cible, avec ajustement éventuel des accès ou fermeture de la source.

Prototype

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

Arguments

NameTypeDirDescription
SourceProcessHandleHANDLEinHandle vers le processus possédant SourceHandle. Nécessite PROCESS_DUP_HANDLE.
SourceHandleHANDLEinLe handle dans le processus source à dupliquer.
TargetProcessHandleHANDLEinHandle vers le processus destination. NULL n'est autorisé qu'avec DUPLICATE_CLOSE_SOURCE dans Options.
TargetHandlePHANDLEoutReçoit le nouveau handle valide dans le processus cible. Facultatif.
DesiredAccessACCESS_MASKinMasque d'accès pour le nouveau handle. Ignoré si Options contient DUPLICATE_SAME_ACCESS.
HandleAttributesULONGinDrapeaux comme OBJ_INHERIT ou OBJ_PROTECT_CLOSE appliqués au nouveau handle.
OptionsULONGinCombinaison de DUPLICATE_CLOSE_SOURCE et/ou DUPLICATE_SAME_ACCESS / DUPLICATE_SAME_ATTRIBUTES.

IDs de syscalls par version de Windows

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

Module noyau

ntoskrnl.exeNtDuplicateObject

APIs liées

DuplicateHandleNtOpenProcessNtOpenProcessTokenNtDuplicateTokenNtClose

Stub du syscall

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

Notes non documentées

NtDuplicateObject porte le SSN `0x3C` de Windows 10 1507 à Windows 11 24H2 — courbe plate rare dans la table, ce qui rend les stubs syscall directs hardcodés faciles. En interne il passe par ObDuplicateObject qui valide PROCESS_DUP_HANDLE sur le processus source et re-référence l'objet sous-jacent dans la table de handles de la cible. Les drapeaux `Options` (DUPLICATE_SAME_ACCESS, DUPLICATE_SAME_ATTRIBUTES, DUPLICATE_CLOSE_SOURCE) sont la partie la plus exploitable côté offensif : DUPLICATE_SAME_ACCESS contourne le rognage de DACL au moment de la duplication, et DUPLICATE_CLOSE_SOURCE est la primitive bon marché pour le vol de handle.

Usage courant par les malwares

Deux schémas dominent. D'abord, **contrebande de handle** entre processus : un implant dans un processus peu privilégié ouvre une cible plus privilégiée avec PROCESS_DUP_HANDLE et utilise NtDuplicateObject pour en extraire un handle de token ou de processus (à combiner avec NtOpenProcessToken pour aspirer des tokens — brique classique du `steal_token` de Cobalt Strike). Ensuite, **vol de handle pour accès aux credentials** : quand un service haut-intégrité détient déjà un handle vers LSASS (antimalware, EDR, lsm.exe dans certains cas), dupliquer ce handle dans le processus de l'attaquant évite tout appel à NtOpenProcess sur lsass.exe — ce qui défait les détections PPL/EDR les plus courantes. Documenté dans le trick d'héritage de handles de Hidden Bee, le mode `--use-valid-sig` de NanoDump, et abusé par Lazarus et FIN7. DUPLICATE_CLOSE_SOURCE sert aussi aux ransomwares pour forcer la fermeture des verrous fichier détenus par Office/SQL avant chiffrement.

Opportunités de détection

Les EDR hookent NtDuplicateObject dans ntdll pour les événements de duplication inter-processus ; côté noyau, ObRegisterCallbacks (ObjectPreCallback / ObjectPostCallback) sur PsProcessType et PsThreadType se déclenche indépendamment du hooking usermode et reste le pivot autorisé. Sysmon Event ID 10 (ProcessAccess) signale l'ouverture source avec accès PROCESS_DUP_HANDLE, souvent révélatrice si la source est lsass.exe. Surveiller les processus ouverts en DUP_HANDLE mais jamais en VM_OPERATION/VM_READ — schéma classique de contrebande de handle. ETW Microsoft-Windows-Kernel-Audit-API-Calls (GUID `e02a841c-75a3-4fa7-afc8-ae09cf9b7f23`) émet un événement de duplication avec PID source et cible.

Exemples de syscalls directs

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,
    );
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20