4

I came across a document called The Ultimate Anti-Reversing Reference, which describes various Anti-Debugging techniques. in point 4.Thread Local Storage There is a mention

Thread Local Storage callbacks are called whenever a thread is created or destroyed (unless the process calls the kernel32 DisableThreadLibraryCalls() or the ntdll LdrDisableThreadCalloutsForDll() functions). That includes the thread that is created by Windows when a debugger attaches to a process. The debugger thread is special, in that its entrypoint does not point inside the image. Instead, it points inside kernel32.dll. Thus, a simple debugger detection method is to use a Thread Local Storage callback to query the start address of each thread that is created. The check can be made using this 32-bit code to examine the 32-bit Windows environment on either the 32-bit or 64-bit versions of Windows:

 push eax mov eax, esp push 0 push 4 push eax ;ThreadQuerySetWin32StartAddress push 9 push -2 ;GetCurrentThread() call NtQueryInformationThread pop eax cmp eax, offset l1 jnb being_debugged ... 

I wrote the c++ code as below

bool fooBar() { uintptr_t dwStartAddress; TFNNtQueryInformationThread ntQueryInformationThread = (TFNNtQueryInformationThread)GetProcAddress( GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationThread"); if (ntQueryInformationThread != 0) { NTSTATUS status = ntQueryInformationThread( (HANDLE)-2, (_THREADINFOCLASS)9, &dwStartAddress, sizeof(dwStartAddress), nullptr); cout << hex << "dwStartAddress: 0x" << dwStartAddress << dec << endl; } 

and I'm running this inside the TLS callbacks

EXTERN_C #ifdef _M_X64 #pragma const_seg (".CRT$XLB") const #else #pragma data_seg (".CRT$XLB") #endif PIMAGE_TLS_CALLBACK p_thread_callback = fooBar; #pragma data_seg () #pragma const_seg () 

The value of dwStartAddress points to the .exe module, not to kernel32.dll as stated in the text. Regardless if I just run the exe or run in debugger or attach a debugger to the process (tho I'm not very experienced with attaching so maybe I'm doing something wrong here).

Am I doing something wrong, or the text is wrong / no longer valid?

5
  • 1
    Are you running an infinite loop inside the main function of your executable? The TLS callback should be called for every thread created. Once before main and once when you attach to the process while it’s running. Commented Jul 17, 2018 at 22:21
  • I used system("pause") but I changed to inifite loop now and still no output that would suggest that TSL callback was called 2nd time Commented Jul 18, 2018 at 0:29
  • I think I tried everything and I just can't get a debugger to spawn thread as described in this document. Im using windows 10. If anyone could check it also on windows 10 and maybe some other OS I would be really thankful Commented Jul 19, 2018 at 14:01
  • Today I ran into this again, but in my case a TLS callback was called on debug attach. I’ll show you tomorrow Commented Jul 20, 2018 at 1:05
  • My debugged some more and it seems there is call to LdrDisableThreadCalloutsForDll with address of kernel32.dll as argument which... well should disable this for kernel32.dll spawned threads. Now the question is how to disable this call. This call is made BEFORE main, BEFORE crtMain, BEFORE TLS callbacks. When could it be? On dll loading? Commented Jul 20, 2018 at 10:02

1 Answer 1

7

When a debugger wants to attach to a process it will do the following things (see the DebugActiveProcess implementation on ReactOS):

  1. Connect to the debuggee with DbgUiConnectToDbg
  2. Tell the kernel to start debugging the process with NtDebugActiveProcess
  3. Issue a DbgBreakPoint in the attached-to process with DbgUiIssueRemoteBreakin

The DbgUiIssueRemoteBreakin function creates a thread in the debuggee pointed at DbgUiRemoteBreakin, which in turn calls DbgBreakPoint.

This anti-debug trick no longer works from Windows 7 and onwards because the DbgUiIssueRemoteBreakin creates the DbgUiRemoteBreakin thread with the SkipThreadAttach flag (relevant blogpost). This causes the newly-created thread to not call DllMain or TLS callbacks with the DLL_THREAD_ATTACH or DLL_THREAD_DETACH reason.

2
  • 1
    Indeed that seems to be an issue. Could you also please confirm if I am correct on this one: Not only the callbacks are not called due to SkipThreadAttach flag, but also even if they were called, the Thread Entry Point would point into ntdll.dll not into kernel32.dll right? Commented Jul 23, 2018 at 18:24
  • 1
    Yes. The start address of the thread is in DbgUiRemoteBreakin, which is an export of ntdll.dll Commented Jul 23, 2018 at 18:25

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.