> Windows Syscalls
ntoskrnl.exeT1106T1027

NtAlertThreadByThreadId

Despierta un único hilo (identificado por su TID) parado en NtWaitForAlertByThreadId — la cara kernel de WakeByAddressSingle.

Prototipo

NTSTATUS NtAlertThreadByThreadId(
  HANDLE ThreadId
);

Argumentos

NameTypeDirDescription
ThreadIdHANDLEinTID del hilo a despertar, como valor con forma de HANDLE (campo ClientId.UniqueThread del TEB).

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070x6Ewin10-1507
Win10 16070x6Ewin10-1607
Win10 17030x6Fwin10-1703
Win10 17090x6Fwin10-1709
Win10 18030x6Fwin10-1803
Win10 18090x6Fwin10-1809
Win10 19030x6Fwin10-1903
Win10 19090x6Fwin10-1909
Win10 20040x70win10-2004
Win10 20H20x70win10-20h2
Win10 21H10x70win10-21h1
Win10 21H20x70win10-21h2
Win10 22H20x70win10-22h2
Win11 21H20x70win11-21h2
Win11 22H20x70win11-22h2
Win11 23H20x70win11-23h2
Win11 24H20x71win11-24h2
Server 20160x6Ewinserver-2016
Server 20190x6Fwinserver-2019
Server 20220x70winserver-2022
Server 20250x71winserver-2025

Módulo del kernel

ntoskrnl.exeNtAlertThreadByThreadId

APIs relacionadas

WakeByAddressSingleWakeByAddressAllWaitOnAddressNtWaitForAlertByThreadIdNtAlertThreadRtlWakeAddressSingle

Stub del syscall

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

Introducido en Windows 8 y muy usado desde Windows 10 como el sustrato kernel de `WakeByAddressSingle` / `WakeByAddressAll`. Junto con `NtWaitForAlertByThreadId`, este par implementa alertas por hilo que *no* requieren objeto kernel nombrado (ni Event, ni Mutex, ni Semaphore). El estado de sincronización es simplemente una dirección en modo usuario que el kernel hashea en una tabla de espera por proceso; el kernel solo necesita el TID destino y no hace lookup en el object manager, lo que abarata muchísimo la ruta de despacho. Las SRWLOCK, el nuevo `WaitOnAddress` y la implementación moderna de variables de condición de ntdll se apoyan en esta primitiva.

Uso común por malware

Sincronización de baja señal para sleep-masks, planificación de beacons y bombas de comandos. Como no se crea ni se nombra ningún objeto kernel, no hay artefactos `\BaseNamedObjects\…` que herramientas como ProcessHacker / SystemInformer puedan mostrar — ese es el principal atractivo frente a `NtSetEvent` / `NtWaitForSingleObject`. Algunas variantes de sleep-mask derivadas de Cobalt Strike y los backends de planificación más recientes de Sliver usan `WaitOnAddress` (y por tanto este syscall) para aparcar hilos workers entre ciclos de beacon. A mediados de 2026 sigue siendo un syscall de *baja señal* maliciosa: la misma ruta la usa cualquier programa Win32 moderno con SRWLOCK o std::mutex en MSVC, el volumen legítimo entierra el uso malicioso.

Oportunidades de detección

Prácticamente indetectable por sí solo — `NtAlertThreadByThreadId` lo invocan la liberación de SRWLOCK, el wake de variable de condición y todo unlock de `std::mutex` C++17/20 que encuentra un waiter. Los EDR no lo hookean porque el suelo de ruido es enorme. El único ángulo útil es la *combinación* con telemetría de sleep-mask: retornos cortos y periódicos de NtWaitForAlertByThreadId combinados con NtAlertThreadByThreadId desde un único hilo no-sistema, en un proceso que también hace beaconing, *más* una región de código RX-only — ahí el syscall es señal corroborativa, nunca primaria.

Ejemplos de syscalls directos

cStealth wake of a parked worker

// Replace SetEvent on a globally named event with WaitOnAddress/WakeByAddressSingle
// to avoid creating an object visible to handle-listers.
typedef NTSTATUS(NTAPI* fnNtAlertThreadByThreadId)(HANDLE);

void PokeWorker(DWORD workerTid) {
    HMODULE n = GetModuleHandleA("ntdll.dll");
    fnNtAlertThreadByThreadId p = (fnNtAlertThreadByThreadId)
        GetProcAddress(n, "NtAlertThreadByThreadId");
    p((HANDLE)(ULONG_PTR)workerTid);
}

asmx64 direct stub (Win11 24H2 SSN)

; SSN 0x71 on win11-24h2 / winserver-2025. 0x70 on most prior 20H2+ builds.
NtAlertThreadByThreadId PROC
    mov  r10, rcx
    mov  eax, 71h
    syscall
    ret
NtAlertThreadByThreadId ENDP

rustPair with WaitOnAddress equivalent

// Wake a worker parked in NtWaitForAlertByThreadId without ever instantiating
// a named kernel object. Useful in implants that want to look like a normal
// Win32 program using SRWLOCK.
use windows_sys::Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress};

type NtAlertThreadByThreadId = unsafe extern "system" fn(tid: isize) -> i32;

pub unsafe fn wake_worker(tid: u32) -> i32 {
    let n = GetModuleHandleA(b"ntdll.dll\0".as_ptr());
    let addr = GetProcAddress(n, b"NtAlertThreadByThreadId\0".as_ptr()).unwrap();
    let f: NtAlertThreadByThreadId = std::mem::transmute(addr);
    f(tid as isize)
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20