> Windows Syscalls
ntoskrnl.exeT1622T1106T1497

NtSetInformationThread

Définit une propriété d'un thread via l'énumération THREADINFOCLASS — notamment ThreadHideFromDebugger.

Prototype

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

Arguments

NameTypeDirDescription
ThreadHandleHANDLEinHandle vers le thread cible. Utilisez NtCurrentThread() ((HANDLE)-2) pour le thread appelant.
ThreadInformationClassTHREADINFOCLASSinÉnum sélectionnant la propriété à définir, ex. ThreadHideFromDebugger (0x11), ThreadBreakOnTermination (0x12).
ThreadInformationPVOIDinTampon contenant la nouvelle valeur. Pour ThreadHideFromDebugger, il est ignoré et peut être NULL.
ThreadInformationLengthULONGinTaille en octets du tampon ThreadInformation. 0 pour ThreadHideFromDebugger.

IDs de syscalls par version de Windows

Version 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

Module noyau

ntoskrnl.exeNtSetInformationThread

APIs liées

SetThreadInformationNtQueryInformationThreadNtSetInformationProcessNtContinueDbgUiRemoteBreakin

Stub du 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

Notes non documentées

Le SSN de NtSetInformationThread est `0xD` sur tous les builds Windows modernes, ce qui en fait un point d'ancrage privilégié pour les stubs syscall faits main. La surface intéressante est l'énumération `THREADINFOCLASS` : `ThreadHideFromDebugger = 0x11` fait que KiDispatchException ne notifie plus le débogueur attaché des exceptions levées par ce thread, rendant invisibles les points d'arrêt et le single-step. `ThreadBreakOnTermination = 0x12` active le bit BreakOnTermination de l'EPROCESS afin que la fin du thread provoque un bug-check — parfois utilisé comme piège anti-altération brutal. La plupart des autres classes (ThreadIdealProcessor, ThreadPriorityBoost) sont totalement bénignes.

Usage courant par les malwares

ThreadHideFromDebugger est *le* primitif anti-debug en mode utilisateur — appelé sur le thread principal (et souvent sur chaque worker) au démarrage pour faire taire x64dbg, WinDbg ou le débogueur local d'IDA. Les protecteurs commerciaux (VMProtect, Themida, Enigma) y recourent ; les crypters du commerce, les droppers de documents et les outils post-ex Cobalt Strike soucieux d'échapper aux bacs à sable d'analystes aussi. Certaines familles abusent également de ThreadBreakOnTermination pour qu'un kill forcé par un EDR provoque un BSOD du système — une évasion destructive vue chez quelques wipers et rootkits agressifs.

Opportunités de détection

Depuis Windows 10 1809, le noyau émet un événement ETW Threat Intelligence (`EtwTiLogSetInformationThread`) dès que ThreadHideFromDebugger est activé ; Defender for Endpoint et la plupart des EDR modernes le consomment — c'est le signal le plus fiable, car même un appelant en syscall direct ne peut pas le supprimer depuis le user-mode. Microsoft-Windows-Threat-Intelligence est un provider ETW protégé, l'inscription nécessite donc PPL/AntiMalware Light. Les hooks usermode sur `ntdll!NtSetInformationThread` sont systématiquement contournés par syscalls directs ; la télémétrie noyau reste l'unique couche fiable. Corréler avec ThreadInformationClass == 0x11 pour limiter le bruit.

Exemples de syscalls directs

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

Mappings MITRE ATT&CK

Last verified: 2026-05-20