> Windows Syscalls
ntoskrnl.exeT1027.011T1027T1106

NtSignalAndWaitForSingleObject

Señaliza atómicamente un objeto dispatcher y espera sobre otro en una única transición libre de carrera.

Prototipo

NTSTATUS NtSignalAndWaitForSingleObject(
  HANDLE         SignalHandle,
  HANDLE         WaitHandle,
  BOOLEAN        Alertable,
  PLARGE_INTEGER Timeout
);

Argumentos

NameTypeDirDescription
SignalHandleHANDLEinHandle al objeto a señalizar (event con acceso SET, mutant propiedad del llamador o semaphore con MODIFY_STATE). Debe ser uno de los tipos dispatcher señalizables.
WaitHandleHANDLEinHandle al objeto a esperar (cualquier objeto dispatcher esperable — event, mutant, semaphore, process, thread, timer, ...). Debe otorgar SYNCHRONIZE.
AlertableBOOLEANinSi TRUE, la espera puede ser interrumpida por APC user-mode (NtQueueApcThread), retornando STATUS_USER_APC.
TimeoutPLARGE_INTEGERinTimeout opcional: NULL = infinito, negativo = unidades relativas 100ns, positivo = tiempo absoluto. STATUS_TIMEOUT (0x102) señaliza expiración.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070x19Awin10-1507
Win10 16070x1A3win10-1607
Win10 17030x1A9win10-1703
Win10 17090x1ACwin10-1709
Win10 18030x1AEwin10-1803
Win10 18090x1AFwin10-1809
Win10 19030x1B0win10-1903
Win10 19090x1B0win10-1909
Win10 20040x1B6win10-2004
Win10 20H20x1B6win10-20h2
Win10 21H10x1B6win10-21h1
Win10 21H20x1B8win10-21h2
Win10 22H20x1B8win10-22h2
Win11 21H20x1C1win11-21h2
Win11 22H20x1C5win11-22h2
Win11 23H20x1C5win11-23h2
Win11 24H20x1C8win11-24h2
Server 20160x1A3winserver-2016
Server 20190x1AFwinserver-2019
Server 20220x1BEwinserver-2022
Server 20250x1C8winserver-2025

Módulo del kernel

ntoskrnl.exeNtSignalAndWaitForSingleObject

APIs relacionadas

SignalObjectAndWaitNtWaitForSingleObjectNtWaitForMultipleObjectsNtSetEventNtCreateEvent

Stub del syscall

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

La implementación kernel detrás de `SignalObjectAndWait`. La propiedad definitoria es la *atomicidad*: la señal y la espera ocurren como una sola transición de hilo, sin ventana de instrucciones intermedia donde otro hilo pueda observar la señal y hacer rendez-vous antes de que este hilo se haya estacionado en su objeto de espera. Comparar con el par ingenuo `SetEvent(a); WaitForSingleObject(b, ...)`, que son dos syscalls distintos con un hueco visible en userland. El SSN deriva en cada release mayor (`0x1B0` 1903, `0x1B6` 2004, `0x1C8` 24H2 / Server 2025). El flag Alertable es lo que hace viables los sleep-masks tipo Ekko: la espera puede ser terminada por un APC, pero la secuencia señalar-luego-esperar permanece atómica.

Uso común por malware

La piedra angular de los diseños de **sleep-mask** libres de carrera. El patrón Ekko / Foliage usa tres etapas de timer-queue cuyo handoff está coreografiado por `NtSignalAndWaitForSingleObject` — en cada límite de fase, el hilo del beacon señaliza atómicamente «fase N terminada, estoy estacionado» y espera sobre el siguiente event que la cadena de gadgets ROP disparará. Sin atomicidad, un escáner de memoria que observe el flag «estoy cifrado» y carrere a leer memoria antes de que la espera se registre puede ganar una ventana de carrera sub-microsegundo — la atomicidad colapsa esa ventana a cero. La misma primitiva se usa en la sincronización clásica de Windows (el `_endthreadex` del runtime C la usa para señalizar el event de fin de hilo y auto-terminar, liberando atómicamente el estado por hilo del runtime). Algunos canales C2 red-team también la usan para handoff atómico de dequeue en pools de workers lock-free.

Oportunidades de detección

Por sí solo, NtSignalAndWaitForSingleObject es mainstream — los thread pools de Win32 (`PTP_WORK`), el runtime C y muchas primitivas internas de .NET pasan por él. *No* es una señal primaria útil. El patrón interesante es la correlación con la cadena telemétrica de sleep-mask Ekko: creación de timer-queue (`NtCreateTimer`), tres o más events creados consecutivamente, una región RWX bloqueada vía `NtLockVirtualMemory`, y luego un patrón `NtSignalAndWaitForSingleObject` con timeouts en el rango de segundos a minutos. Los escáneres de memoria que snapshotean bytes del working set a intervalos aleatorios — en lugar de reaccionar a syscalls — esquivan toda esta clase de evasión porque no dependen de observar el handoff atómico.

Ejemplos de syscalls directos

asmx64 stub (Win11 24H2 SSN 0x1C8)

; Direct syscall stub for NtSignalAndWaitForSingleObject
NtSignalAndWaitForSingleObject PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 1C8h         ; SSN (Win11 24H2 / Server 2025)
    syscall
    ret
NtSignalAndWaitForSingleObject ENDP

cEkko-style atomic sleep handoff

// Phase handoff in an Ekko sleep mask: atomically signal "encrypted,
// parked" and wait for the wake event. No userland gap for a scanner
// to race into.
#include <windows.h>

typedef NTSTATUS (NTAPI *pNtSignalAndWaitForSingleObject)(
    HANDLE Signal, HANDLE Wait, BOOLEAN Alertable, PLARGE_INTEGER Timeout);

NTSTATUS SleepHandoff(HANDLE h_encrypted_done, HANDLE h_wake) {
    pNtSignalAndWaitForSingleObject NtSignalAndWaitForSingleObject =
        (pNtSignalAndWaitForSingleObject)GetProcAddress(
            GetModuleHandleA("ntdll.dll"), "NtSignalAndWaitForSingleObject");
    // Wait alertable so a timer APC can wake us; infinite timeout.
    return NtSignalAndWaitForSingleObject(
        h_encrypted_done, h_wake, TRUE, NULL);
}

rustRendezvous primitive (race-free)

// SignalObjectAndWait wraps NtSignalAndWaitForSingleObject.
// Use it to atomically release a producer event and park on the consumer
// event in a lock-free queue worker.
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::Threading::SignalObjectAndWait;

pub unsafe fn handoff(signal: HANDLE, wait: HANDLE, ms: u32) -> u32 {
    SignalObjectAndWait(signal, wait, ms, /* alertable */ 0)
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20