From d61f7e5cd054687eac440970edd2021d149d9847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sat, 29 Nov 2025 18:24:47 +0100 Subject: [PATCH] [NTOS:PS] Implement Vista+ NtQueryInformationThread(ThreadHideFromDebugger) support (#8486) https://ntquery.wordpress.com/2014/03/29/anti-debug-ntsetinformationthread/ indicates that starting Vista, `NtQueryInformationThread()` supports querying the `ThreadHideFromDebugger` information. This was noticed by contributor Mikhail Tyukin, while testing anti-cheat protected NT6+ games written with Unity. See also https://ntdoc.m417z.com/threadinfoclass#threadhidefromdebugger-17 for the buffers descriptions. --- ntoskrnl/include/internal/ps_i.h | 20 +++++++++++----- ntoskrnl/ps/query.c | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/ntoskrnl/include/internal/ps_i.h b/ntoskrnl/include/internal/ps_i.h index fa20bbb385e..1a9f3e81d01 100644 --- a/ntoskrnl/include/internal/ps_i.h +++ b/ntoskrnl/include/internal/ps_i.h @@ -503,12 +503,20 @@ static const INFORMATION_CLASS_INFO PsThreadInfoClass[] = ), /* ThreadHideFromDebugger */ - IQS_SAME - ( - CHAR, - ULONG, - ICIF_SET | ICIF_SET_SIZE_VARIABLE - ), + { +#if (NTDDI_VERSION >= NTDDI_VISTA) + sizeof(BOOLEAN), /* Query support only on Vista and above */ +#else + 0, +#endif + sizeof(ULONG), // UCHAR + 0, /* No size for Set */ + sizeof(ULONG), +#if (NTDDI_VERSION >= NTDDI_VISTA) + ICIF_QUERY | +#endif + ICIF_SET + }, /* ThreadBreakOnTermination */ IQS_SAME diff --git a/ntoskrnl/ps/query.c b/ntoskrnl/ps/query.c index 49419af1af1..a0916bc0253 100644 --- a/ntoskrnl/ps/query.c +++ b/ntoskrnl/ps/query.c @@ -3243,6 +3243,46 @@ NtQueryInformationThread( ObDereferenceObject(Thread); break; +#if (NTDDI_VERSION >= NTDDI_VISTA) + case ThreadHideFromDebugger: + { + /* Set the return length */ + Length = sizeof(BOOLEAN); + + if (ThreadInformationLength != Length) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + /* Reference the thread */ + Status = ObReferenceObjectByHandle(ThreadHandle, + Access, + PsThreadType, + PreviousMode, + (PVOID*)&Thread, + NULL); + if (!NT_SUCCESS(Status)) + break; + + /* Protect write with SEH */ + _SEH2_TRY + { + *(PBOOLEAN)ThreadInformation = Thread->HideFromDebugger; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Get exception code */ + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + + /* Dereference the thread */ + ObDereferenceObject(Thread); + break; + } +#endif /* (NTDDI_VERSION >= NTDDI_VISTA) */ + case ThreadBreakOnTermination: /* Set the return length */