> Windows Syscalls
ntoskrnl.exeT1106

NtCompareObjects

Liefert STATUS_SUCCESS, wenn zwei Handles auf dasselbe zugrundeliegende Kernel-Objekt verweisen.

Prototyp

NTSTATUS NtCompareObjects(
  HANDLE FirstObjectHandle,
  HANDLE SecondObjectHandle
);

Argumente

NameTypeDirDescription
FirstObjectHandleHANDLEinErstes zu vergleichendes Handle; jede Access-Maske wird akzeptiert.
SecondObjectHandleHANDLEinZweites zu vergleichendes Handle; jede Access-Maske wird akzeptiert.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x95win10-1507
Win10 16070x96win10-1607
Win10 17030x97win10-1703
Win10 17090x98win10-1709
Win10 18030x99win10-1803
Win10 18090x99win10-1809
Win10 19030x99win10-1903
Win10 19090x99win10-1909
Win10 20040x9Bwin10-2004
Win10 20H20x9Bwin10-20h2
Win10 21H10x9Bwin10-21h1
Win10 21H20x9Bwin10-21h2
Win10 22H20x9Bwin10-22h2
Win11 21H20x9Dwin11-21h2
Win11 22H20x9Dwin11-22h2
Win11 23H20x9Dwin11-23h2
Win11 24H20x9Fwin11-24h2
Server 20160x96winserver-2016
Server 20190x99winserver-2019
Server 20220x9Dwinserver-2022
Server 20250x9Fwinserver-2025

Kernel-Modul

ntoskrnl.exeNtCompareObjects

Verwandte APIs

CompareObjectHandlesNtDuplicateObjectNtQueryObjectNtQuerySystemInformation

Syscall-Stub

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

Eingeführt in Windows 10 1507, um User-Mode einen ehrlichen Gleichheitstest für Kernel-Objekte zu geben. Vor diesem Syscall war der einzige verlässliche Weg, zu wissen, ob zwei Handles dasselbe Objekt aliasten, ein Stapel fehleranfälliger Heuristiken (Objektnamen vergleichen, wo verfügbar, PIDs für Prozess-Handles vergleichen, usw.). Intern löst `NtCompareObjects` beide Handles über `ObReferenceObjectByHandle` zu ihrem zugrundeliegenden `_OBJECT_HEADER *` auf, testet Pointer-Gleichheit und dereferenziert dann beide. Die Implementierung steht in `ObCompareObjectsForCommonSecurity`. Rückgabe ist binär: `STATUS_SUCCESS` (gleiches Objekt), `STATUS_NOT_SAME_OBJECT` (verschiedene Objekte) oder eine der üblichen `STATUS_INVALID_HANDLE`-Varianten. Typen müssen nicht übereinstimmen — vergleicht man ein `Process`-Handle mit einem `Token`-Handle, kommt einfach `STATUS_NOT_SAME_OBJECT`. Es gibt *keinen* öffentlichen Win32-Wrapper; das Nächste ist `CompareObjectHandles`, ausschließlich über das Windows SDK als ucrt-Inline ausgeliefert, das in das undokumentierte `CompareObjectHandles` von `KernelBase.dll` aufruft (Win10 1809+).

Häufige Malware-Nutzung

Geringes Malware-Signal. Wird an zwei Stellen verwendet: (1) EDR-Introspektionscode, der bestätigen will, dass ein dupliziertes Handle noch dasselbe Zielobjekt referenziert, und (2) bestimmte Implant-Designs (Cobalt-Strike-BOFs, einige Sliver-Erweiterungen) nutzen ihn als leichten OPSEC-Check, bevor sie z. B. `NtDuplicateObject` auf einem Handle aufrufen, das sie verdächtigen, bereits von einem EDR-kontrollierten Prozess gegrabbt worden zu sein. Auch ein praktischer Handle-zu-Handle-Gleichheitstest in Post-Exploitation-Tooling, das die System-Handle-Tabelle (`NtQuerySystemInformation(SystemHandleInformation)`) durchläuft und Aliase deduplizieren will. Er *umgeht* nichts selbst — ist eine Primitive für andere Primitiven.

Erkennungs­möglichkeiten

Kein ETW-Provider emittiert Per-Call-Telemetrie für diesen Syscall, und Sysmon legt ihn nicht offen. Defender alarmieren generell nicht auf `NtCompareObjects`, weil legitime Nutzung selten-aber-echt ist (KernelBase!CompareObjectHandles wird von Teilen von `Win32k`, `ImmersiveShell` und `RuntimeBroker.exe` aufgerufen). Interessant wird es nur, wenn ein unsigniertes oder frisch geladenes Modul plötzlich viele `NtCompareObjects` in einer engen Schleife gegen die System-Handle-Tabelle absetzt — dieses Muster ist die Post-Exploitation-Handle-Walk-Signatur, der Aufruf selbst ist aber ein schlechter Primärindikator.

Direkte Syscall-Beispiele

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtCompareObjects (SSN 0x9F on Win11 24H2 / Server 2025)
NtCompareObjects PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 9Fh          ; SSN — drifts; resolve dynamically for portability
    syscall
    ret
NtCompareObjects ENDP

cDeduplicate aliased handles after NtQuerySystemInformation

// Walks a handle list and collapses entries that alias the same object —
// a common post-exploitation cleanup before reporting unique findings.
for (ULONG i = 0; i < count; ++i) {
    for (ULONG j = i + 1; j < count; ++j) {
        if (NtCompareObjects(handles[i], handles[j]) == STATUS_SUCCESS) {
            // aliased -> drop handles[j] from the result set
            handles[j] = NULL;
        }
    }
}

rustCompareObjectHandles wrapper (windows-sys)

// Cargo: windows-sys = "0.59" (Win32_Foundation, Win32_System_Threading)
// CompareObjectHandles is a thin KernelBase wrapper over NtCompareObjects.
use windows_sys::Win32::Foundation::{CompareObjectHandles, HANDLE};

fn same_object(a: HANDLE, b: HANDLE) -> bool {
    unsafe { CompareObjectHandles(a, b) != 0 }
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20