TLS回调函数
0x01 TLS介绍
TLS(Thread Local Storage,线程局部储存),主要用于给线程独立的传值,由于线程不拥有进程的资源,所以几个同一进程的几个线程需要独立赋值时的需要通过TLS技术。每个线程创建时都会分配一个index所以,这个索引index是全局变量,线程根据index来获取其他线程传过来的返回值。TLS有一个特点,就是它通常在程序EP前就要运行,所以起始TLS才是个程序真正的开始。利用这一特点,可以用来进行的程序的反调试。
一句话介绍:执行于进程或线程的创建与终止,早于EP(Entry Point) 那么我们怎么才能知道一个程序是否含有TLS回调函数呢?
0x02 PE TLS Table
编程中启用了TLS功能,PE头文件中就会设置TLS表
然后找到TLS Table
再找到TLS函数开始的地址
即0x401990
在IDA中验证一下(IDA是能帮你识别出TLS函数的)
0x03 TLS函数调用顺序
假设main函数里写了创建用户线程(ThreadProc)
0x01 DLL_PROCESS_ATTACH 进程启动 Reason=1
进程的主线程调用main()函数前,已经注册的TLS回调函数(TLS_CALLBACK1、TLS_CALLBACK2)会先被调用执行。
0x02 DLL_THREAD_ATTACH 线程启动 Reason=2
所有TLS回调函数完成调用后,main()函数开始调用执行,创建用户线程(ThreadProc)前,TLS回调函数会被再次调用执行。
0x03 DLL_THREAD_DETACH 线程结束 Reason=3
TLS回调函数全部执行完毕后,ThreadProc()线程函数开始调用执行。其执行完毕后Reason=3(DLL_THREAD_DETACH),TLS回调函数被调用执行。
0x04 DLL_PROCESS_DETACH 进程结束 Reason=0
ThreadProc()线程函数执行完毕后,一直在等待线程终止的main()函数(主线程)也会终止。此时Reason=0(DLL_PROCESS__DETACH),TLS回调函数最后一次被调用执行。
【miniLCTF2022】TWIN 复现
0x01 陷阱
main函数是纯纯骗你的,解密出来
后面你能发现一件惊奇的事情,那就是main函数根本就不会被执行!
0x02 找到TLS函数开始的地址
IDA已经帮你解析出了TLS函数,虽然是空的(出题人加了点❀)
也可以像文章开头一样,在PE中就找到了TLS的开始地址。
花指令清不清无所谓。
这个TLS函数中,你能清晰的发现DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH(我已加注释)
如果不过PEB反调试的话,将不会设置第二个TLS函数,那么后面会得不到正确的flag。
hObject = CreateFileMappingA(0, 0, 4u, 0, 0x1000u, Name_FLAG);创建名字为FLAG的文件映射对象,用于进程间通信。 *(_DWORD *)input = MapViewOfFile(hObject, 0xF001Fu, 0, 0, 0x1000u);存了内存映射文件,便于后面的共享内存。 简而言之,就是创建一个名为FLAG的文件映射对象,把input指向的地址设置成一块共享的内存,这样就可以在子进程里对input这块内存进行修改,实现加密。 来自云之君的Blog
0x03 第一个TLS函数
在TLS函数开始地址处下个断点,开始跟进。
过掉反调试
发现其设置了第二个TLS函数
继续跟进,发现字符串混淆,即对字符串异或0x7f还原
第一个TLS的末尾,开始输入字符,随便输入12345678
第一个TLS函数算是结束了,根据TLS函数的机制,他将会执行第二个TLS函数。
0x04 进入第二个TLS
此时,就可以去第二个TLS开始地址下断点,直接F9跳过去。
我们就能得到第二个TLS函数
获取WriteFile 的地址
HOOK WriteFile地址,到目标函数(其实就是Sub_0x401650,之后可以知道是修改tmp文件中XXTEA的z的右移值)
第二个TLS函数就结束了
0x05 进程结束,进入PROCESS_DETACH
进程结束,根据TLS函数的机制,接下来返回到DLL_PROCESS_DETACH
进入CreatTmp函数
创建子进程tmp文件,可以在同目录下发现已经创建好的tmp文件。
跟进WriteFile函数中,发现了之前HOOK的函数
继续向下调试,能发现很关键的函数
0x06 主进程调试子进程
此时我们要关注Tmp子进程,进入tmp文件,其包含了一个XXTEA,以及一些对Delta修改的指令。
tmp文件中还检测了是否有调试器
我们将IDA的根目录进行修改,改成adi.exe 😋,就能过了。
我们重新调试,在关键点XOR处下断点,就能得到最终的Delta值。
0x07 Cat Flag
第一段flag
已知XXTEA的key和密文(注意key[1]已被赋值为144)
第二段flag
第二个XXTEA函数(sub_4012C0)
两段flag组合即为最后的flag
0x08 后话
这题涉及的知识点挺多的,最后还是要感谢P.Z和云之君等大佬的博客和视频,帮助我一步步了解这题的运行过程。感谢这些师傅们,Thanks♪(・ω・)ノ。ORZ。 这题遇到的麻烦也不少:调试时,不知道何原因,tmp子进程一直创建失败,在Process_Exployer软件中也看不到tmp进程的踪影。导致调试时一直卡在WaitForDebugEvent处。但是放到win10虚拟机中,问题又解决了。搞不懂都。
0x09总结知识点
· 理清TLS函数的调用过程,TLS>Main->TLS(这道题Main根本都没执行,加解密与flag的判断,全在TLS函数中) · 主进程调试子进程,以及其接受异常处理事件,这题秀我一脸了属于是(原来可以酱紫玩)。 · PEB反调试,并不是看到PEB检测就无脑修改ZF标志符,主进程调试子进程,所以子进程中的PEB检测反而不需要过,盲目的过反调试会带来后果。 · HOOK函数,此题HOOK函数修改tmp文件中XXTEA的z的右移位数 · 字符串的混淆
评论区