1 Introduction to TLS technology
Thread Local Storage (TLS) is a mechanism that Windows provides to address the simultaneous access of multiple threads in a process to global variables. TLS can simply be done by the operating system on its behalf to complete the mutex process, or the user can write their own function of controlling the semaphore. When a thread in a process accesses a predetermined amount of memory space, the operating system invokes the system's default or user-defined semaphore function to ensure the integrity and correctness of the data.
The principle of TLS-based anti-debugging is to execute the instrumentation debugger code before the actual entry point code is executed, using the TLS callback function to implement it. The effect of the TLS anti-debugging implementation, like, is to execute the anti-debug code and exit the program before the OD dynamic debugger loads the program to the entry point. In addition, with TLS booting, some viruses can be run before the debugger starts, because some debuggers are cut in at the main entry point of the program.
1.1 TLS callback function
When the user chooses to use their own callback function, during the application initialization phase, the system will invoke a user-written callback function to perform the appropriate initialization and some other initialization work. This call must be completed before the program actually starts executing to the entry point to ensure that the program executes correctly.
The TLS callback function has the following function prototypes:
void Ntapi tlscallbackfunction (PVOID Handle, DWORD Reason, PVOID Reserve);
1.2 Data structure of TLS
The executable file for Windows is in PE format, in the PE format, specifically for the TLS data opened a space, the specific location of image_nt_headers. OPTIONALHEADER.DATADIRECTORY[IMAGE_DIRECTORY_ENTRY_TLS]. The elements of which datadirectory have the following structure:
typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size;} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
For the DataDirectory element of TLS, the virtualaddress member points to a struct, which defines the memory address, the TLS callback function address, and some other information that the access needs to be mutually exclusive.
2 Concrete realization and principle
Full use of the TLS callback function before the program entry point to obtain the program control of the characteristics of the TLS callback function in the anti-debugging operation than the traditional anti-debugging techniques have a better effect.
2.1 VS2015 X64 Release Demo
The VC compilers provided by Microsoft support the use of TLS directly in the program, which will be done using VS2015.
#include <Windows.h>#include <tchar.h>#pragma comment (lib, "Ntdll.lib")extern "C"NTSTATUS Ntapi ntqueryinformationprocess (HANDLE hprocess, ulong Infoclass, PVOID Buffer, ulong Length, Pulong returnlengt h);#define Ntcurrentprocess () (HANDLE)-1voidNtapi __stdcall Tls_callback (PVOID dllhandle, DWORD Reason, PVOID Reserved) {if(Isdebuggerpresent ()) {MessageBoxA (NULL,"Tls_callback:debugger detected!","TLS Callback", MB_OK);//ExitProcess (1);}Else{MessageBoxA (NULL,"Tls_callback:no Debugger Present!...","TLS Callback", MB_OK); }}voidNtapi __stdcall tls_callback_2 (PVOID dllhandle, DWORD Reason, PVOID Reserved) {HANDLE debugport = NULL;if(! Ntqueryinformationprocess (Ntcurrentprocess (),7,//Processdebugport&debugport,//If debugger is present, it'll be set To-1 | Otherwise, it is set to NULL sizeof(HANDLE), NULL)) {if(DebugPort) {MessageBoxA (NULL,"Tls_callback2:debugger detected!","TLS Callback", mb_iconstop); }Else{MessageBoxA (NULL,"Tls_callback2:no Debugger Detected","TLS Callback", mb_iconinformation); } }}//linker Spec notifies the linker PE file to create a TLS directory, note the difference between X86 and X64#ifdef _m_ix86#pragma COMMENT (linker, "/include:__tls_used")#pragma COMMENT (linker, "/include:__tls_callback")#else#pragma COMMENT (linker, "/include:_tls_used")#pragma COMMENT (linker, "/include:_tls_callback")#endif//Create TLS segmentExtern_c#ifdef _m_x64#pragma const_seg (". Crt$xlb ")Const#else#pragma data_seg (". Crt$xlb ")#endif//END linker//TLS Import defines multiple callback functionsPimage_tls_callback _tls_callback[] = {tls_callback, tls_callback_2,0};#pragma data_seg ()#pragma const_seg ()//endintApientry _tWinMain (hinstance hinstance, hinstance hprevinstance, LPTSTR lpCmdLine,intnCmdShow) {MessageBoxA (NULL,"Hello wolrd!...:)","Main ()", MB_OK);return 0;}
To use TLS in a program, you must create a separate data segment for the TLS data, populate it with related data, and notify the linker to add data to the PE file header for TLS data. To do this, you need to add the following code to the program source file:
//linker Spec notifies the linker PE file to create a TLS directory, note the difference between X86 and X64#ifdef _m_ix86#pragma COMMENT (linker, "/include:__tls_used")#pragma COMMENT (linker, "/include:__tls_callback")#else#pragma COMMENT (linker, "/include:_tls_used")#pragma COMMENT (linker, "/include:_tls_callback")#endif//Create TLS segmentExtern_c#ifdef _m_x64#pragma const_seg (". Crt$xlb ")Const#else#pragma data_seg (". Crt$xlb ")#endif//END linker//TLS Import defines multiple callback functionsPimage_tls_callback _tls_callback[] = {tls_callback, tls_callback_2,0};#pragma data_seg ()#pragma const_seg ()//end
Where the _tls_callback[] array holds all the TLS callback function pointers. It is worth noting that the array must end with a null pointer, and each callback function in the array is called when the program is initialized, and the programmer can add as needed. But programmers should not assume that the operating system has called the callback function in any order. This requires a certain degree of independence in the TLS callback function for the counter-debug operation.
The compiler and linker use several special variables to support implicit TLS. Specifically, the variable _tls_used (X86 under Variable type image_tls_directory,x64 under Variable type image_tls_directory64) is created by the C run-time library. When statically linked, the variable represents the TLS directory structure and is used by the final image file (for the reason of the name decoration, the extern "C" link is required in C + + and the storage type is externally introduced because the CRT code has created the variable). The TLS directory is part of the PE file header, which tells the loader how to manage thread local variables, and when linking, the linker looks for variable _tls_used (note: Use double underline __tls_used under X86, use single underscore _tls_used under X64), and ensure that it overlaps with the TLS directory in the final PE file.
The source code for declaring variable _tls_used in the C run-time library is located in the Tlssup.c file (published with Visual Studio). The _tls_used standard is declared in the following manner:
#ifdef _win64_crtalloc (". rdata$t")extern ConstImage_tls_directory64 _tls_used ={(ulonglong) &_tls_start,//start of TLS data(ULONGLONG) &_tls_end,//end of TLS data(ULONGLONG) &_tls_index,//Address of Tls_index(ULONGLONG) (&__xl_a+1),//Pointer to call back array(ULONG)0,//size of TLS zero fill(ULONG)0 //Characteristics};#else/* _win64 * /_crtalloc (". rdata$t")extern ConstImage_tls_directory _tls_used ={(ULONG) (ULONG_PTR) &_tls_start,//start of TLS data(ULONG) (ULONG_PTR) &_tls_end,//end of TLS data(ULONG) (ULONG_PTR) &_tls_index,//Address of Tls_index(ULONG) (ULONG_PTR) (&__xl_a+1),//Pointer to call back array(ULONG)0,//size of TLS zero fill(ULONG)0 //Characteristics};#endif/* _win64 * /
Similarly, CRT code provides a mechanism that allows a program to register a series of TLS callback functions that have a similar signature to DllMain. (These callback functions can exist in the master image file, and DllMain is not possible.) The callback function type is the PIMAGE_TLS_CALLBACK,TLS directory that points to a null-terminated callbacks array (in the actual test, the callback function is called sequentially.) However, programmers should not assume that the operating system calls callback functions in any order.
The second parameter in the TLS callback function determines that the function is called in that case (like the DllMain function):
- Dll_process_attach: When a new process is created, it executes when the main thread is initialized.
- Dll_process_detach: Refers to execution when a process terminates.
- Dll_thread_attach: Refers to when a new thread is created, but does not include the main thread.
- Dll_thread_detach: Refers to execution when all threads terminate, but does not include the main thread.
It should be noted that, when the TLS callback function executes, the VC runtime Msvcrt.dll,mfc.dll and so on are not loaded, and cannot use C library functions (such as printf). If necessary, you should use the LoadLibrary () function to load the corresponding library and use GetProcAddress () to get the address of the function. However, such operations may cause related events in the debugger to be triggered and are not recommended for such operations.
TLS callbacks are not used for generic PE files (in practice, most use DllMain to accomplish a thread-independent initial chemical work). However, TLS callback support is fully operational. In order to use the TLS callback support provided by the CRT, we need to declare a store in the ". Crt$xlx "is the name of the section, where x is a letter located between A and Z. For example, the following code snippet:
#pragma section(“.CRT$XLY”,long,read)extern “C” __declspec(allocate(“.CRT$XLY”))PIMAGE_TLS_CALLBACK _xl_y = MyTlsCallback;
This strange section name is required because of the reason that the TLS callback pointer needs to be sorted in memory. To understand the purpose of this particular declaration, you need to first understand how the compiler and linker organize the data in the PE file.
In PE files, except for header data, the rest is stored in different sections, which are memory areas that have the same property (also protected property) collection. The keyword __declspec (allocate ("Section-name") tells the linker to place the contents of its scope within the specified section in the final PE file. The linker additionally supports merging similar-named sections into one large sections function. This feature is activated by using the section name prefix +$+ any string. The linker merges a section with the same section name prefix as a large sections.
The linker merges the similar sections in dictionary order (sort the string after $ ). This means that in memory, the section is located. The variables in the CRT$XLB "are located in the section." CRT$XLA "in the back of the variable position, but in the section". CRT$XLZ "in front of the variable. The C run-time library takes advantage of this feature of the linker to create a null-terminated array of TLS callbacks (the section ". A null pointer is placed in the CRT$XLZ ". Therefore, in order to ensure that the declared function pointer is inside the TLS callback array, it must be placed in the section. CRT$XLx "in.
2.2 Specific implementation of the callback function 2.2.1 using isdebuggerpresent to detect the debugger
Microsoft has provided us with an API function to detect whether the current program is being debugged, which is isdebuggerpresent (), and the implementation of this function is simple:
语法 BOOL WINAPI IsDebuggerPresent(void);参数 该函数没有参数返回值 如果当前进程运行在调试器的上下文,返回值为非零值。 如果当前进程没有运行在调试器的上下文,返回值是零。
2.2.2 Make DebugPort Detection debugger
Each process has a data structure, eprocess, which is inside the kernel that the system uses to identify and manage the basic data structure of each win process. This structure contains an important field, DebugPort, if a process is not being debugged, then it is null, otherwise he is a pointer, and this member of the win process holds the LPC port object pointer that is used to receive debug events. When debugging occurs, The system sends debug information to this port.
WinXP because the kernel object Debugobject is used specifically for debugging, DebugPort points to a Debugobject object, either to the LPC port or to the Debug object, which is used to pass debug events. So the object pointed to in DebugPort, we are called the debug port. This port is the link between the debugger process and the debug process, which is sent by this port to the debugger process by the debug program's events.
HANDLEDebugPort= NULL;if(!Ntqueryinformationprocess (Ntcurrentprocess (),7,//Processdebugport &DebugPort,//If debugger is present, it'll be set To-1 | Otherwise, it is set to NULLsizeofHANDLE),NULL)) {if(DebugPort) {MessageBoxA (NULL,"Tls_callback2:debugger detected!","TLS Callback", mb_iconstop); }Else{MessageBoxA (NULL,"Tls_callback2:no Debugger Detected","TLS Callback", mb_iconinformation); } }
3 actual test 3.1 test direct execution
The test method is to double-click Execute directly in Explorer. It is executed directly after compiling with VS2015, and the program runs normally. The program calls Tls_callback in the expected order, tls_callback_2 two callback functions, and finally calls the _tWinMain function, which pops up the appropriate window at the time of the program run and prompts that the debugger is not detected.
3.2 Testing with debugger loading
The test method is to debug using a debugger loaded with VS2015, and a program generated using Ollydebug loading. Test results: The sequence of calls to both programs is the same as not using the debugger, which calls the TLS callback function first, and both of the debuggers prompt for a debugger to be detected.
With ollydbg (installed with anti-debugging plug-in OD will be immune, it is best to remove the plug-in first) test results such as, the program will also detect the debugger.
4 Summary
Traditional anti-debugging techniques have a weakness: they all take anti-debugging measures after the program actually starts executing. In fact, before the anti-debug code is executed, the debugger has a lot of time to affect the execution of the program, and even can insert a breakpoint command at the entrance of the program to debug the program. For programs that are compiled with the C + + language, the problem is usually more severe, and a large piece of code that is inserted by the C + + compiler is executed before the main () function executes, which also gives the debugger an opportunity to influence program execution.
By using the TLS technique as the carrier of the anti-debugging technique, a technique is implemented to execute the anti-debug code before the entrance of the program. The technology itself does not affect the execution of the program, but it can effectively prevent debugging of the debugger. Can greatly enhance the anti-piracy ability of the program software. If we can combine the traditional technology, the anti-debugging technology will be developed to a new height.
WIN10 X64 with TLS for reverse debugging