NtSetInformationThread
Setzt eine Thread-Eigenschaft über die THREADINFOCLASS-Enumeration — bekannt durch ThreadHideFromDebugger.
Prototyp
NTSTATUS NtSetInformationThread( HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| ThreadHandle | HANDLE | in | Handle auf den Ziel-Thread. NtCurrentThread() ((HANDLE)-2) für den aufrufenden Thread. |
| ThreadInformationClass | THREADINFOCLASS | in | Enum, der die zu setzende Eigenschaft auswählt, z. B. ThreadHideFromDebugger (0x11), ThreadBreakOnTermination (0x12). |
| ThreadInformation | PVOID | in | Puffer mit dem neuen Wert. Bei ThreadHideFromDebugger wird er ignoriert und darf NULL sein. |
| ThreadInformationLength | ULONG | in | Größe des ThreadInformation-Puffers in Bytes. 0 für ThreadHideFromDebugger. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0xD | win10-1507 |
| Win10 1607 | 0xD | win10-1607 |
| Win10 1703 | 0xD | win10-1703 |
| Win10 1709 | 0xD | win10-1709 |
| Win10 1803 | 0xD | win10-1803 |
| Win10 1809 | 0xD | win10-1809 |
| Win10 1903 | 0xD | win10-1903 |
| Win10 1909 | 0xD | win10-1909 |
| Win10 2004 | 0xD | win10-2004 |
| Win10 20H2 | 0xD | win10-20h2 |
| Win10 21H1 | 0xD | win10-21h1 |
| Win10 21H2 | 0xD | win10-21h2 |
| Win10 22H2 | 0xD | win10-22h2 |
| Win11 21H2 | 0xD | win11-21h2 |
| Win11 22H2 | 0xD | win11-22h2 |
| Win11 23H2 | 0xD | win11-23h2 |
| Win11 24H2 | 0xD | win11-24h2 |
| Server 2016 | 0xD | winserver-2016 |
| Server 2019 | 0xD | winserver-2019 |
| Server 2022 | 0xD | winserver-2022 |
| Server 2025 | 0xD | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
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
Undokumentierte Hinweise
Die SSN von NtSetInformationThread ist `0xD` über alle modernen Windows-Builds hinweg — ein bevorzugter Anker für handgeschriebene Syscall-Stubs. Spannend ist die `THREADINFOCLASS`-Enum: `ThreadHideFromDebugger = 0x11` führt dazu, dass KiDispatchException Ausnahmen dieses Threads keinem angehängten Debugger mehr meldet — Breakpoints und Single-Step werden unsichtbar. `ThreadBreakOnTermination = 0x12` setzt das BreakOnTermination-Bit im EPROCESS, sodass das Beenden des Threads einen Bug-Check auslöst — gelegentlich als grobe Anti-Tamper-Falle missbraucht. Andere Klassen (ThreadIdealProcessor, ThreadPriorityBoost) sind harmlos.
Häufige Malware-Nutzung
ThreadHideFromDebugger ist *die* klassische Anti-Debug-Primitive im User-Mode — wird beim Start auf dem Hauptthread (und oft auf jedem Worker) gesetzt, um x64dbg, WinDbg und den lokalen IDA-Debugger zu blenden. Kommerzielle Protectoren (VMProtect, Themida, Enigma) nutzen es; ebenso Standard-Crypter, Dokument-Dropper und Cobalt-Strike-Post-Ex-Tools, die Analyst-Sandboxen umgehen wollen. Manche Familien missbrauchen außerdem ThreadBreakOnTermination, sodass das gewaltsame Beenden des Implant-Threads durch ein EDR den Host bluescreent — eine destruktive Umgehungstechnik, die in Wipern und aggressiven Rootkits beobachtet wird.
Erkennungsmöglichkeiten
Ab Windows 10 1809 sendet der Kernel beim Setzen von ThreadHideFromDebugger ein ETW-Threat-Intelligence-Event (`EtwTiLogSetInformationThread`); Defender for Endpoint und die meisten modernen EDRs konsumieren es — das hochwertigste verfügbare Signal, da direkter Syscall-Aufruf es im User-Mode nicht unterdrücken kann. Microsoft-Windows-Threat-Intelligence ist ein geschützter ETW-Provider, das Abonnieren erfordert PPL/AntiMalware Light. User-Mode-Hooks auf `ntdll!NtSetInformationThread` werden routinemäßig durch direkte Syscalls umgangen — Kernel-Telemetrie ist die einzige verlässliche Schicht. Mit ThreadInformationClass == 0x11 korrelieren, um Rauschen zu minimieren.
Direkte Syscall-Beispiele
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 ENDPcIndirect 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) }
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20