title: TLS回调函数实现反调试.md
date: 2022-06-16 23:40:49.231
updated: 2022-06-16 23:41:11.924
url: /archives/tls回调函数实现反调试
categories:
tags:
- 逆向
TLS回调函数实现反调试
TLS-线程局部存储
先于我们OEP执行
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<tchar.h>
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
#include <winternl.h>
#pragma comment(linker,"/INCLUDE:__tls_used")
// 告诉链接器我要用到TLS
DWORD isDebug = 0;
void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved) {
if (Reason == DLL_PROCESS_ATTACH)
{
::MessageBoxA(0,"TLS函数执行1",0,0);
//不接受内核调试信息
/*NtSetInformationThread(GetCurrentThread(),ThreadHideFromDebugger,0,0);
NtSetInformationProcess(GetCurrentProcess(),ProcessDebugPort,(PVOID)&isDebug,sizeof(DWORD),NULL);
*/
}
}
void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved) {
if (Reason == DLL_PROCESS_ATTACH)
{
::MessageBoxA(0, "TLS函数执行2", 0, 0);
}
}
int main()
{
::MessageBoxA(0,"Main函数启动了",0,0);
}
//新建一段数据放入TLS这个目录里面
#pragma data_seg(".CRT$XLX")
PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, NULL };
#pragma data_seg()
描述了TLS的结构体
对应
可以理解为函数指针的数组
实例
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
#include <winternl.h>
#pragma comment(linker,"/INCLUDE:__tls_used")
// 告诉链接器我要用到TLS
DWORD dwDebugPort;
typedef NTSTATUS(__stdcall* pNtQueryInformationProcess)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength
);
void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved) {
if (Reason == DLL_PROCESS_ATTACH)
{
::MessageBoxA(0,"TLS函数执行1",0,0);
//不接受内核调试信息
HMODULE hModule = LoadLibrary(TEXT("Ntdll.dll"));
pNtQueryInformationProcess ntQueryInformationProcess = (pNtQueryInformationProcess)GetProcAddress(hModule, "NtQueryInformationProcess");
ntQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort, &dwDebugPort, sizeof(dwDebugPort), NULL);//dwDebugPort 为0表示没用被调试,反之则是
}
}
//void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved) {
//
// if (Reason == DLL_PROCESS_ATTACH)
// {
// ::MessageBoxA(0, "TLS函数执行2", 0, 0);
//
// }
//
//}
int main()
{
char str[] = "wust_is_good!";
for (int i = 0; i < 14; ++i) {
str[i] ^= dwDebugPort;
}
::MessageBoxA(NULL,str,"提示", MB_OK);
}
//新建一段数据放入TLS这个目录里面
#pragma data_seg(".CRT$XLX")
PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, /*TLS_CALLBACK2,*/ NULL };
#pragma data_seg()
如果直接运行
本地调试运行
一堆乱码
由于dwDebugPort是全局变量, 发现不是调试,置为0,0异或任何数都是该数本身
题目 Dest0g3 520迎新赛 tttea
注意到是xxtea的特征值
加密方式也是xxtea,实现部分把输入的44位flag ,组成11位int 类型的数据进行xxtea加密,最后与密文对比
原本是直接写的东西,直接魔改xxtea直接弄,发现跑出来是乱码,直接动态调试
构造flag
flag{12345678912345678912345678912345678911}
注意到字符串,
发现TLS和反调试函数
该字符串地址后24正好是key的位置
由于TLS一般在程序难以发现
最好使用查看PE文件的软件看各个段
PE结构里->数据目录表(常见的导出表、导入表等)->TLS表
所以,加入TLS_CALLBACK,在TLS表里会找到TLS回调函数,这是找到TLS回调的一个方法
2个反调试
这个是异或
所以真正的delta为0x66403319 ^ 0x12345678,即0x74746561
EXP
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
#define MX (((z>>6^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void xxtea_decode(uint32_t* v, int n, DWORD delta)
{
char* key = (char*)δ
uint32_t y, z, sum;
unsigned p, rounds, e;
rounds = 6 + 52 / n;
sum = rounds * delta;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum -= delta;
} while (--rounds);
}
int main()
{
DWORD delta = 0x74746561;
char enc[] = { 3, 35, 34, 47, 54, 136, 253, 67, 33, 232, 91, 101, 49, 30, 59, 166, 75, 184, 220, 136, 128, 25, 132, 111, 151, 114, 33, 38, 173, 100, 238, 187, 136, 4, 77, 6, 47, 38, 229, 107, 129, 75, 245, 115 };
xxtea_decode((uint32_t*)enc, 11, delta);
printf("%s", enc);
return 0;
}
//Dest0g3{73dd38c2-9d45-4f7a-9bd0-90a1e9907c1}