Thread Hide From Debugger
This nasty anti-debugging trick thwarted me for years, I honestly though my debugger was broken and actively switched between them (OllyDbg, WinDbg, x64dbg, SoftIce). It’s used everywhere because it’s simple and very effective.
Has this ever happened to you? You attach to a process with a debugger and place a breakpoint and it immediately crashes when it gets hit? God, I hate this trick. You find it everywhere because it’s simple and effective at thwarting reverse engineering.
Here’s what it looks like. I have a C++ program called NoBreakpointsAllowed.exe
and when I place a breakpoint on a call the Sleep
it gets hit and dies.
Ubiquity
I won’t go into the super technical details because they’re well explained elsewhere, but the code is effectively
#include <windows.h>
int main() {
...
// Hide from debugger 0x11
NtSetInformationThread(GetCurrentThread(), 0x11, 0, 0);
...
}
It’s really that simple. The real annoyance is once this has been set, you can’t unset it and only in the kernel can you tell it’s been set. Essentially you have a couple options to neutralizing this trick:
- If you open the process you can breakpoint user land
NtSetInformationThread
and watch for calls with0x11
as theThreadInformationClass
parameter. This is a pain becauseNtSetInformationThread
is called a lot of incredibly mundane reasons. - You can write a shim dll that’s loaded as a dependent dll and hook it yourself to make sure it never gets called, but this will change the CRC of the process and modifications to the process are often detected by anti-cheat software. (An option might be to shim another windows dll that’s loaded, I use
XInput.dll
pretty often, but this brings on new challenges of redoing work everytime windows updates). - You can unset the flag from kernel mode using techniques osronline would furvently disapprove of and tell you not to do.
So I went and did option 3.
KWorld
https://github.com/colinsenner/KWorld
KWorld goes through all threads in the process and removes the ThreadHideFromDebugger flag from each thread. This allows the process to be debugged without crashing.
Since offsets in the kernel _ETHREAD
and _EPROCESS
structures can differ between Windows versions, I lookup the offsets once at runtime. We need to find the offset of the ThreadHideFromDebugger
flag in the _ETHREAD
structure. I do this by finding the function PsIsThreadTerminating
in ntoskrnl.exe
. The first instruction of this function is
Where 560h
is the offset of the CrossThreadFlags in the _ETHREAD structure. Bit 3 of CrossThreadFlags is the HideFromDebugger flag.
Once we have this information we can enumerate all process threads and clear the flag. This should be relatively robust to offset changes in the kernel structures.