TLS(线程局部存储)以及基于TLS技术的反调试技术
来源:互联网 发布:windows Api编程过程 编辑:程序博客网 时间:2024/05/18 02:29
在说TLS反调试技术之前,我们先看一下TLS技术是什么。
TLS是各线程的独立的数据存储空间,使用TLS技术可在线程内部独立使用或者修改进程的全局数据或是静态数据,就像对待自身的局部变量一样。TLS回调函数常用于反调试,因为TLS回调函数运行会先于EP代码执行。
若在编程中使用了TLS功能,PE头文件中就会设置TLS表项目
IMAGE_TLS_DIRECTORY结构体定义如下:
ypedef struct _IMAGE_TLS_DIRECTORY64 { ULONGLONG StartAddressOfRawData; ULONGLONG EndAddressOfRawData; ULONGLONG AddressOfIndex; // PDWORD ULONGLONG AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *; DWORD SizeOfZeroFill; union { DWORD Characteristics; struct { DWORD Reserved0 : 20; DWORD Alignment : 4; DWORD Reserved1 : 8; } DUMMYSTRUCTNAME; } DUMMYUNIONNAME;} IMAGE_TLS_DIRECTORY64;typedef struct _IMAGE_TLS_DIRECTORY32 { DWORD StartAddressOfRawData; DWORD EndAddressOfRawData; DWORD AddressOfIndex; // PDWORD DWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * DWORD SizeOfZeroFill; union { DWORD Characteristics; struct { DWORD Reserved0 : 20; DWORD Alignment : 4; DWORD Reserved1 : 8; } DUMMYSTRUCTNAME; } DUMMYUNIONNAME;} IMAGE_TLS_DIRECTORY32;
需要注意的是,AddressOfCallBack成员指向的是一个含有TLS回调函数的数组,这表明可以注册多个TLS回调函数。
TLS回调函数定义如下:
typedef VOID(NTAPI *PIMAGE_TLS_CALLBACK) ( PVOID DllHandle, //模块句柄 DWORD Reason, //调用TLS回调函数时机 PVOID Reserved // );第二参数有四个状态:
#define DLL_PROCESS_ATTACH 1 #define DLL_THREAD_ATTACH 2 #define DLL_THREAD_DETACH 3 #define DLL_PROCESS_DETACH 0我们可以看到TLS回调函数很像DllMain()函数。下面我们来一个例子加深对TLS的印象。
#include "stdafx.h"#include <Windows.h>#pragma comment(linker,"/INCLUDE:__tls_used")void PrintAtShell(WCHAR* wzMessage);DWORD WINAPI ThreadProc(LPVOID lParam);void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved);void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved);int main(){ HANDLE ThreadHandle = NULL; PrintAtShell(L"main() start!\r\n"); ThreadHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); WaitForSingleObject(ThreadHandle, 60 * 1000); CloseHandle(ThreadHandle); PrintAtShell(L"main() end!\r\n"); return 0;}void PrintAtShell(WCHAR* wzMessage){ //检索指定设备句柄,STD_OUTPUT_HANDLE指示标准输出设备 HANDLE StdHandle = GetStdHandle(STD_OUTPUT_HANDLE); //将输入内容显示到控制台屏幕上,类似于printf,但是因为TLS回调函数先于main()函数执行,所以有可能printf()函数无法正常使用 WriteConsole(StdHandle, wzMessage,lstrlen(wzMessage), NULL, NULL);}DWORD WINAPI ThreadProc(LPVOID lParam){ PrintAtShell(L"ThreadProc() start!\r\n"); PrintAtShell(L"ThreadProc() end!\r\n"); return 0;}void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved){ WCHAR wzMessage[80] = { 0 }; wsprintf(wzMessage, L"TLS_CALLBACK1():DllHandle = %X,Reason = %d\r\n", DllHandle, Reason); PrintAtShell(wzMessage);}void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved){ WCHAR wzMessage[80] = { 0 }; wsprintf(wzMessage, L"TLS_CALLBACK2():DllHandle = %X,Reason = %d\r\n", DllHandle, Reason); PrintAtShell(wzMessage);}#pragma data_seg(".CRT$XLX")PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1,TLS_CALLBACK2,0 };#pragma data_seg()输出结果:
TLS_CALLBACK1():DllHandle = 930000,Reason = 1
TLS_CALLBACK2():DllHandle = 930000,Reason = 1
main() start!
TLS_CALLBACK1():DllHandle = 930000,Reason = 2
TLS_CALLBACK2():DllHandle = 930000,Reason = 2
ThreadProc() start!
ThreadProc() end!
TLS_CALLBACK1():DllHandle = 930000,Reason = 3
TLS_CALLBACK2():DllHandle = 930000,Reason = 3
main() end!
TLS_CALLBACK1():DllHandle = 930000,Reason = 0
TLS_CALLBACK2():DllHandle = 930000,Reason = 0
因为我们定义了两个TLS回调函数,当进程刚刚启动时调用TLS回调函数,打印出1,然后main函数启动,之后又启动一个线程,触发TLS回调函数2,然后线程启动,关闭线程之后,调用TLS3,最后进程结束,触发0事件。相信这时候对TLS回调函数有了一定理解了吧,现在我们开始正题,如何利用TLS回调函数进行反调试。
我们知道了TLS回调函数在main()函数执行之前执行,所以,我们可以定义一个TLS回调函数去检测当前进程有没有被调试。我们知道调试器一般会下int 3断点进行调试,我们只需在函数入口处检查是否下了int 3断点即可判断是否被调试。所以我们直接看代码吧:
#include "stdafx.h"#include <Windows.h>#pragma comment(linker,"/INCLUDE:__tls_used")void NTAPI MY_TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved);int main(){ MessageBox(NULL, L"运行", L"警告", 0); return 0;}void NTAPI MY_TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved){ if (Reason == DLL_PROCESS_ATTACH) { //获得当前Exe模块基地址 PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL); PIMAGE_NT_HEADERS32 pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew); //执行函数入口 BYTE* OEP = (BYTE*)(pNtHeader->OptionalHeader.AddressOfEntryPoint + (DWORD)pDosHeader); //判断函数入口处有没有被调试器下int3断点 for (int i = 0; i < 200; i++) { if (OEP[i] == 0xCC) { MessageBox(NULL, L"调试", L"警告", 0); ExitProcess(0); } } }}#pragma data_seg(".CRT$XLX")PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { MY_TLS_CALLBACK,0 };#pragma data_seg()运行结果:
未调试状态:
用x32dbg或者OD调试状态:
0 0
- TLS(线程局部存储)以及基于TLS技术的反调试技术
- 一种基于TLS的高级反调试技术
- 一种基于TLS的高级反调试技术
- 线程局部存储(TLS)的使用
- 线程局部存储(TLS)
- 线程局部存储(TLS)
- 线程局部存储(TLS)
- 线程局部存储(TLS)
- 线程局部存储(TLS)
- 线程局部存储(TLS)
- 线程局部存储TLS
- 线程局部存储TLS
- TLS--线程局部存储
- 线程局部存储(TLS)
- 线程局部存储(TLS)
- TLS--线程局部存储
- 线程局部存储TLS
- TLS--线程局部存储
- 安装Fedora要做的25件事情
- java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()L
- Java注解
- Spark取到Kafka,出现ZK和Kafka offset不一致
- ACM程序设计 书中题目 B
- TLS(线程局部存储)以及基于TLS技术的反调试技术
- RTP/RTCP协议介绍
- 详解Java的Spring框架中的注解的用法
- C语言 内存管理
- 全排列问题的JAVA代码
- Linux 系统下 NVIDIA 显卡驱动,GNOME 桌面环境不兼容
- 洛谷 3654_First Step (ファーストステップ)_模拟
- 数组排序sort()用法
- Python面向对象编程(5)——类的特殊方法