> Windows Syscalls
ntoskrnl.exeT1622T1106T1497

NtSetInformationThread

Establece una propiedad de un hilo mediante la enumeración THREADINFOCLASS — célebremente ThreadHideFromDebugger.

Prototipo

NTSTATUS NtSetInformationThread(
  HANDLE          ThreadHandle,
  THREADINFOCLASS ThreadInformationClass,
  PVOID           ThreadInformation,
  ULONG           ThreadInformationLength
);

Argumentos

NameTypeDirDescription
ThreadHandleHANDLEinHandle al hilo objetivo. Use NtCurrentThread() ((HANDLE)-2) para el hilo llamante.
ThreadInformationClassTHREADINFOCLASSinEnum que selecciona la propiedad a establecer, p. ej. ThreadHideFromDebugger (0x11), ThreadBreakOnTermination (0x12).
ThreadInformationPVOIDinBúfer con el nuevo valor. Para ThreadHideFromDebugger se ignora y puede ser NULL.
ThreadInformationLengthULONGinTamaño en bytes del búfer ThreadInformation. 0 para ThreadHideFromDebugger.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070xDwin10-1507
Win10 16070xDwin10-1607
Win10 17030xDwin10-1703
Win10 17090xDwin10-1709
Win10 18030xDwin10-1803
Win10 18090xDwin10-1809
Win10 19030xDwin10-1903
Win10 19090xDwin10-1909
Win10 20040xDwin10-2004
Win10 20H20xDwin10-20h2
Win10 21H10xDwin10-21h1
Win10 21H20xDwin10-21h2
Win10 22H20xDwin10-22h2
Win11 21H20xDwin11-21h2
Win11 22H20xDwin11-22h2
Win11 23H20xDwin11-23h2
Win11 24H20xDwin11-24h2
Server 20160xDwinserver-2016
Server 20190xDwinserver-2019
Server 20220xDwinserver-2022
Server 20250xDwinserver-2025

Módulo del kernel

ntoskrnl.exeNtSetInformationThread

APIs relacionadas

SetThreadInformationNtQueryInformationThreadNtSetInformationProcessNtContinueDbgUiRemoteBreakin

Stub del syscall

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

El SSN de NtSetInformationThread es `0xD` en todos los builds modernos de Windows, lo que lo convierte en ancla preferida para stubs de syscall hechos a mano. La superficie interesante es el enum `THREADINFOCLASS`: `ThreadHideFromDebugger = 0x11` hace que KiDispatchException no notifique al depurador adjunto las excepciones lanzadas por ese hilo, invisibilizando breakpoints y single-step. `ThreadBreakOnTermination = 0x12` activa el bit BreakOnTermination del EPROCESS para que el cierre del hilo provoque un bug-check — a veces usado como burdo cable trampa anti-tamper. Otras clases (ThreadIdealProcessor, ThreadPriorityBoost) son completamente benignas.

Uso común por malware

ThreadHideFromDebugger es *el* primitivo anti-debug clásico de modo usuario — invocado en el hilo principal (y a menudo en cada worker) al arrancar para silenciar x64dbg, WinDbg y el depurador local de IDA. Protectores comerciales (VMProtect, Themida, Enigma) lo usan; también los crypters de mercado, droppers documentales y herramientas post-ex de Cobalt Strike que quieren esquivar sandboxes de analistas. Algunas familias abusan también de ThreadBreakOnTermination para que, si un EDR mata a la fuerza el hilo del implante, el host genere BSOD — evasión destructiva vista en wipers y rootkits agresivos.

Oportunidades de detección

Desde Windows 10 1809 el kernel emite un evento ETW Threat Intelligence (`EtwTiLogSetInformationThread`) cuando se establece ThreadHideFromDebugger; Defender for Endpoint y la mayoría de los EDR modernos lo consumen — es el indicador más fiable disponible, ya que el llamador por syscall directo no puede suprimirlo desde modo usuario. Microsoft-Windows-Threat-Intelligence es un proveedor ETW protegido y requiere inscripción PPL/AntiMalware Light para suscribirse. Los hooks de usuario sobre `ntdll!NtSetInformationThread` se eluden rutinariamente con syscalls directas, así que la telemetría de kernel es la única capa fiable. Correlacione con ThreadInformationClass == 0x11 para reducir ruido.

Ejemplos de syscalls directos

asmThreadHideFromDebugger direct stub

; SSN 0xD on all modern builds. ThreadInformationClass = 0x11 (ThreadHideFromDebugger).
HideCurrentThread PROC
    sub  rsp, 28h
    mov  rcx, -2              ; NtCurrentThread()
    mov  edx, 11h             ; ThreadHideFromDebugger
    xor  r8, r8               ; ThreadInformation = NULL
    xor  r9d, r9d             ; ThreadInformationLength = 0
    mov  r10, rcx
    mov  eax, 0Dh
    syscall
    add  rsp, 28h
    ret
HideCurrentThread ENDP

cIndirect syscall via ntdll lookup

// Resolves ntdll!NtSetInformationThread and calls it as-is so EDR
// hooks on the prologue still see the call — useful when only the
// ThreadHideFromDebugger event matters and the loader doesn't want
// to look suspicious otherwise.
typedef NTSTATUS(NTAPI* fnNtSetInformationThread)(
    HANDLE, ULONG, PVOID, ULONG);

void HideFromDebugger(void) {
    HMODULE h = GetModuleHandleA("ntdll.dll");
    fnNtSetInformationThread p = (fnNtSetInformationThread)
        GetProcAddress(h, "NtSetInformationThread");
    p((HANDLE)-2, 0x11 /* ThreadHideFromDebugger */, NULL, 0);
}

rustwindows-sys + naked stub

// Cargo: windows-sys = "0.59"
use std::arch::asm;

#[unsafe(naked)]
unsafe extern "system" fn nt_set_information_thread_stub(
    _thread: isize,
    _class: u32,
    _info: *mut u8,
    _len: u32,
) -> i32 {
    asm!(
        "mov r10, rcx",
        "mov eax, 0xD",
        "syscall",
        "ret",
        options(noreturn),
    );
}

pub fn hide_from_debugger() -> i32 {
    unsafe { nt_set_information_thread_stub(-2, 0x11, core::ptr::null_mut(), 0) }
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20