ThreadHideFromDebugger
Calling NtSetInformationThread with ThreadHideFromDebugger detaches a thread from the debugger so its exceptions stop reaching the analyst.
ThreadHideFromDebugger is the value 0x11 of the THREADINFOCLASS enum passed
to the undocumented NtSetInformationThread. When set, the kernel clears the
thread's link to the debug object, so debug events generated by that thread —
exceptions, breakpoints, single steps — are no longer delivered to an attached
debugger.
Malware applies the flag to the thread that runs its sensitive logic, or to every thread it creates, hiding execution from an analyst who is stepping through the code.
How it works
The call takes a thread handle, the information class 0x11, and a NULL
information buffer of length 0. On a hidden thread an int 3 no longer breaks
into the debugger; instead the unhandled exception terminates the process —
which itself can be used as a tripwire.
typedef NTSTATUS (NTAPI *pNtSetInformationThread)(
HANDLE, ULONG, PVOID, ULONG);
#define ThreadHideFromDebugger 0x11
pNtSetInformationThread NtSetInformationThread =
(pNtSetInformationThread)GetProcAddress(
GetModuleHandleW(L"ntdll.dll"), "NtSetInformationThread");
// Hide the current thread from any attached debugger.
NtSetInformationThread(GetCurrentThread(),
ThreadHideFromDebugger, NULL, 0);A sample can also self-test: hide the thread, then execute a breakpoint. If the debugger still catches it, the hide failed (an anti-anti-debug plugin is intercepting the call) and the malware can react.
push 0 ; ThreadInformationLength
push 0 ; ThreadInformation
push 11h ; ThreadHideFromDebugger
push -2 ; GetCurrentThread() pseudo-handle
call NtSetInformationThreadDetection & analysis
Static analysis: Look for imports or dynamic resolution of
NtSetInformationThread / ZwSetInformationThread, combined with the immediate
constant 0x11 pushed as the information class. The NULL buffer and 0
length are reliable signatures for this specific class.
Dynamic analysis: Set a breakpoint on ntdll!NtSetInformationThread and
inspect the second argument. When it equals 0x11, either skip the call or
force the return value to a failure so the flag is never applied. ScyllaHide and
TitanHide both neutralise this class automatically — TitanHide strips the
information class in the kernel before the syscall executes.
Detection rule hint: Flag any call to Nt/ZwSetInformationThread where the
ThreadInformationClass argument is 0x11 and the buffer/length are
NULL/0. In sandbox API logs, a hide call quickly followed by a thread
terminating on an unhandled STATUS_BREAKPOINT is a strong indicator.