> Windows Syscalls
ntoskrnl.exeT1106

NtCompareObjects

Devuelve STATUS_SUCCESS cuando dos handles refieren al mismo objeto kernel subyacente.

Prototipo

NTSTATUS NtCompareObjects(
  HANDLE FirstObjectHandle,
  HANDLE SecondObjectHandle
);

Argumentos

NameTypeDirDescription
FirstObjectHandleHANDLEinPrimer handle a comparar; se acepta cualquier máscara de acceso.
SecondObjectHandleHANDLEinSegundo handle a comparar; se acepta cualquier máscara de acceso.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
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

Módulo del kernel

ntoskrnl.exeNtCompareObjects

APIs relacionadas

CompareObjectHandlesNtDuplicateObjectNtQueryObjectNtQuerySystemInformation

Stub del syscall

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

Notas no documentadas

Añadido en Windows 10 1507 para dar al user-mode un test honesto de igualdad de objetos kernel. Antes de este syscall, la única forma fiable de saber si dos handles aliasaban el mismo objeto era una pila de heurísticas falibles (comparar nombres de objeto cuando disponibles, comparar PIDs para handles de proceso, etc.). Internamente `NtCompareObjects` resuelve ambos handles a su `_OBJECT_HEADER *` subyacente vía `ObReferenceObjectByHandle`, prueba igualdad de punteros y luego dereferencia ambos. La implementación está en `ObCompareObjectsForCommonSecurity`. El retorno es binario: `STATUS_SUCCESS` (mismo objeto), `STATUS_NOT_SAME_OBJECT` (objetos diferentes), o alguna variante usual de `STATUS_INVALID_HANDLE`. Los tipos no necesitan coincidir — comparar un handle `Process` con un handle `Token` simplemente devuelve `STATUS_NOT_SAME_OBJECT`. *No* hay wrapper Win32 público; lo más cercano es `CompareObjectHandles` enviado solo vía Windows SDK como inline ucrt que llama al `CompareObjectHandles` no documentado de `KernelBase.dll` (Win10 1809+).

Uso común por malware

Señal de malware baja. Usado en dos lugares donde aparece: (1) código de introspección EDR que quiere confirmar que un handle duplicado aún apunta al mismo objeto objetivo, y (2) ciertos diseños de implante (BOFs de Cobalt Strike, algunas extensiones Sliver) lo usan como check OPSEC ligero antes de, por ejemplo, llamar `NtDuplicateObject` sobre un handle que sospechan ya fue injertado por un proceso controlado por EDR. También es un test conveniente de igualdad handle-a-handle en herramientas post-explotación que recorren la tabla de handles del sistema (`NtQuerySystemInformation(SystemHandleInformation)`) y quieren deduplicar aliases. *No* bypassea nada por sí mismo — es una primitiva usada por otras primitivas.

Oportunidades de detección

No hay provider ETW que emita telemetría por llamada para este syscall y Sysmon no lo expone. Los defensores generalmente no alertan sobre `NtCompareObjects` porque el uso legítimo es raro-pero-real (KernelBase!CompareObjectHandles es llamado por partes de `Win32k`, `ImmersiveShell` y `RuntimeBroker.exe`). El único punto donde se vuelve interesante es cuando un módulo no firmado o recién cargado emite de repente muchos `NtCompareObjects` en bucle apretado contra la tabla de handles del sistema — ese patrón es la firma de handle-walk post-explotación, pero la llamada en sí es un mal indicador primario.

Ejemplos de syscalls directos

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 }
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20