TLS回调函数
来源:互联网 发布:12海里知乎 编辑:程序博客网 时间:2024/06/13 20:19
本文转载自http://www.cnblogs.com/dliv3/p/6489629.html
作者:dlive
TLS (Thread Local Storage 线程局部存储 )回调函数常用于反调试。
TLS回调函数的调用运行要先于EP代码执行,该特性使它可以作为一种反调试技术使用。
TLS是各线程的独立的数据存储空间,使用TLS技术可在线程内部独立使用或修改进程的全局数据或静态数据,就像对待吱声的局部变量一样。
0x01 PE TLS Table
若在编程中启用了TLS功能,PE头文件中就会设置TLS表(IMAGE_NT_HEARDERS->IMAGE_OPTIONAL_HEADER->IMAGE_DATA_DIRECTORY[9])
可以看到TLS Table的RVA是00009310,找到对应位置如下
TLS Table中比较重要的成员为AddressOfCallbacks,该值指向含有TLS回调函数地址(VA)的数据(一个程序中可以注册多个TLS回调函数)
0x02 TLS回调函数
TLS回调函数是指,每当创建/终止进程的线程时会自动调用执行的函数(前后共调用两次)。创建进程的主线程时也会自动调用回调函数,且其调用执行先于EP代码。
TLS回调函数的声明:
void NTAPI TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved)
DllMain的声明:
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
可以看到两者声明非常相似,第一个参数为模块句柄,即加载地址,第二个参数为调用原因
调用原因有四种
#define DLL_PROCESS_ATTACH 1#define DLL_THREAD_ATTACH 2#define DLL_THREAD_DETACH 3#define DLL_PROCESS_ATTACH 0
TlsTest.cpp
#include <windows.h>//告知连接器使用TLS#pragma comment(linker, "/INCLUDE:__tls_used")void print_console(char* szMsg){ HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); //先于主线程调用执行的TLS回调函数中使用printf可能会发生Runtime Error,可直接调用WriteConsole API WriteConsoleA(hStdout, szMsg, strlen(szMsg), NULL, NULL);}void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved){ char szMsg[80] = {0,}; wsprintfA(szMsg, "TLS_CALLBACK1() : DllHandle = %X, Reason = %d\n", DllHandle, Reason); print_console(szMsg);}void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved){ char szMsg[80] = {0,}; wsprintfA(szMsg, "TLS_CALLBACK2() : DllHandle = %X, Reason = %d\n", DllHandle, Reason); print_console(szMsg);}/* 注册TLS函数 .CRT$XLX的作用 CRT表示使用C Runtime 机制 X表示表示名随机 L表示TLS Callback section X也可以换成B~Y任意一个字符*/#pragma data_seg(".CRT$XLX") //存储回调函数地址 PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, 0 };#pragma data_seg()DWORD WINAPI ThreadProc(LPVOID lParam){ print_console("ThreadProc() start\n"); print_console("ThreadProc() end\n"); return 0;}int main(void){ HANDLE hThread = NULL; print_console("main() start\n"); //创建子线程 hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); //等待子线程结束 WaitForSingleObject(hThread, 60*1000); CloseHandle(hThread); print_console("main() end\n"); return 0;}
主线程调用main前调用TLS回调函数,调用原因为DLL_PROCESS_ATTACH
子线程启动前调用TLS,原因为DLL_THREAD_ATTACH
子线程结束后调用TLS,原因为DLL_THREAD_DETACH
主线程结束后调用TLS的原因为DLL_PROCESS_DETACH
0x03 调试TLS回调函数
在OD调试器的默认设置下调试器会在EP处暂停,WinDbg调试器默认在系统启动断点暂停。
调试TLS回调函数时,因为回调函数代码在EP之前就已经执行了,所以调试选项需要设置暂停于系统断点(system breakpoint), 设置后调试器会在ntdll.dll模块内部的“system startup breakpoint‘处暂停
然后在PE中找到回调函数的地址,下断点调试即可
OD2.0中直接提供暂停在TLS函数的选项
- TLS回调函数
- TLS回调函数
- TLS回调函数的应用
- TLS回调函数的使用
- 171123 逆向-TLS回调函数
- 反调试-通过手动添加TLS回调函数
- .NET 回调函数
- 回调函数
- 回调函数
- 回调函数概念
- 回调函数
- 回调函数
- 回调函数
- 回调函数 相关
- delphi 回调函数
- 回调函数
- 回调函数
- 回调函数学习
- 计算广告学习笔记
- 51信用卡(杭州西溪谷)内推Android开发岗位
- str.split与arr.splice()和arr.slice()详解
- 线性结构
- spring02 ioc
- TLS回调函数
- SVN 将文件还原到之前的指定版本
- android 内存泄露
- Codeforces 842 D. Vitya and Strange Lesson (trie)
- 关于网络(同步、异步、阻塞、非阻塞,select/poll/epoll,rpc/msgqueue,tcpip常见面试题)
- 中文字节长度引起的数据丢失
- CentOS7中如何设置网络自启动
- 健康生活小常识
- Netty 实现 WebSocket 聊天功能