首页 > 学院 > 开发设计 > 正文

调试TLS

2019-11-08 01:56:13
字体:
来源:转载
供稿:网友

前言

看资料时, 看到了TLS, 复习一下. 看看如果程序中带TLS回调, 如何找到并调试. 发现了一个知识点 : 在TLS函数中必须执行一个和Windows消息相关的API, 才会进(DLL_PROCESS_DETACH == Reason) 网上其他TLS资料, 演示TLS时, 都是在TLS中调用MessageBox, 都没有注意这个知识点. 在TLS中弹MessageBox, 实际程序中也不可能这么调用, 本来在TLS中做事, 就是想隐蔽一点,骗骗新手. 在程序中做TLS回调函数, 是在main函数之前跑代码的一种应用.

记录

测试程序

// @file TlsDebug.cpp// @brief TLS试验 on vc6#include "StdAfx.h"#include <windows.h>#include <stdlib.h>#include <time.h>DWord g_StartAddressOfRawData = 0;DWORD g_EndAddressOfRawData = 0;DWORD g_AddressOfIndex = 0; // PDWORDDWORD g_SizeOfZeroFill = 0;DWORD g_Characteristics = 0;DWORD g_dwData1 = 0;DWORD g_dwData2 = 0;VOID NTAPI tlsCb1(PVOID DllHandle, DWORD Reason, PVOID Reserved);VOID NTAPI tlsCb2(PVOID DllHandle, DWORD Reason, PVOID Reserved);// 声明 g_tlsCbAry, 关键是要加 extern "C"extern "C" PIMAGE_TLS_CALLBACK g_tlsCbAry[] = { tlsCb1, tlsCb2, NULL};extern "C" IMAGE_TLS_DIRECTORY32 _tls_used = { (DWORD)& g_StartAddressOfRawData, (DWORD)& g_EndAddressOfRawData, (DWORD)& g_AddressOfIndex, (DWORD)g_tlsCbAry, // 这必须直接赋值为tls回调数组, PIMAGE_TLS_CALLBACK * g_SizeOfZeroFill, g_Characteristics};#pragma comment(linker, "/INCLUDE:__tls_used")int main(int argc, char* argv[]){ if (g_dwData1 > 0) { printf("tlscb1 was called before main/r/n"); } if (g_dwData2 > 0) { printf("tlscb2 was called before main/r/n"); } system("pause"); return 0;}/** run resulttlscb1 was called before maintlscb2 was called before main请按任意键继续. . .*/VOID NTAPI tlsCb1(PVOID DllHandle, DWORD Reason, PVOID Reserved){ // 发现一个很奇怪的问题, TLS函数中, 如果不调用MessageBox, 只有 // (DLL_PROCESS_DETACH == Reason)会来, // 试验结论: // * 在TLS函数中必须执行一个和Windows消息相关的API, 才会进(DLL_PROCESS_DETACH == Reason) // 不能调用MessageBox, 有提示给用户, 太开玩笑了. 调用一个消息检测函数PeekMessageA // * 不能调用内存分配函数(不能调用new 和 malloc, 会失败) // * 这样看起来, 在TLS中做事很受限制. MSG msg; if (DLL_PROCESS_ATTACH == Reason) { PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE); g_dwData1++; } else if (DLL_PROCESS_DETACH == Reason) { g_dwData1--; }}VOID NTAPI tlsCb2(PVOID DllHandle, DWORD Reason, PVOID Reserved){ if (DLL_PROCESS_ATTACH == Reason) { g_dwData2++; } else if (DLL_PROCESS_DETACH == Reason) { g_dwData2--; }}

在逆向时定位TLS函数

用CFF, LordPE, 或者其他工具, 查看PE文件的数据目录表, 可以看到是否存在TLS回调函数. 这里写图片描述 这里写图片描述 这里写图片描述 打开OD或IDA, 定位到CllBackTablerVA(VA值), 可以看到TLS函数有几个(最后一个TLS回调地址后面是0), VA是多少, 就可以分析TLS回调做的具体任务了.

CllBackTablerVA = 00426B40 在OD中定位TLS.CllBackTablerVA

00426B40 >0040100A TlsDebug.0040100A00426B44 00401005 TlsDebug.0040100500426B48 0000000000426B4C 00000000

可以看到TLS回调有2个, 分别是sub_0040100A, sub_00401005 分析TLS回调

00401005 . /E9 D6010000 jmp tlsCb20040100A . |E9 31010000 jmp tlsCb1

定位了TLS回调函数地址, 就可以分析TLS函数的反汇编代码了

00401140 >/> /55 push ebp00401141 |. 8BEC mov ebp, esp00401143 |. 83EC 5C sub esp, 5C00401146 |. 53 push ebx00401147 |. 56 push esi00401148 |. 57 push edi00401149 |. 8D7D A4 lea edi, dword ptr [ebp-5C]0040114C |. B9 17000000 mov ecx, 1700401151 |. B8 CCCCCCCC mov eax, CCCCCCCC00401156 |. F3:AB rep stos dword ptr es:[edi]00401158 |. 837D 0C 01 cmp dword ptr [ebp+C], 10040115C |. 75 32 jnz short 004011900040115E |. 8BF4 mov esi, esp00401160 |. 6A 00 push 0 ; /RemoveMsg = PM_NOREMOVE00401162 |. 68 08010000 push 108 ; |MsgFilterMax = MSG(108)00401167 |. 68 00010000 push 100 ; |MsgFilterMin = WM_KEYDOWN0040116C |. 6A 00 push 0 ; |hWnd = NULL0040116E |. 8D45 E4 lea eax, dword ptr [ebp-1C] ; |00401171 |. 50 push eax ; |pMsg00401172 |. FF15 ECC24200 call dword ptr [<&USER32.PeekMessageA>; /PeekMessageA00401178 |. 3BF4 cmp esi, esp0040117A |. E8 D1000000 call _chkesp0040117F |. 8B0D B89D4200 mov ecx, dword ptr [g_dwData1]00401185 |. 83C1 01 add ecx, 100401188 |. 890D B89D4200 mov dword ptr [g_dwData1], ecx0040118E |. EB 15 jmp short 004011A500401190 |> 837D 0C 00 cmp dword ptr [ebp+C], 000401194 |. 75 0F jnz short 004011A500401196 |. 8B15 B89D4200 mov edx, dword ptr [g_dwData1]0040119C |. 83EA 01 sub edx, 10040119F |. 8915 B89D4200 mov dword ptr [g_dwData1], edx004011A5 |> 5F pop edi004011A6 |. 5E pop esi004011A7 |. 5B pop ebx004011A8 |. 83C4 5C add esp, 5C004011AB |. 3BEC cmp ebp, esp004011AD |. E8 9E000000 call _chkesp004011B2 |. 8BE5 mov esp, ebp004011B4 |. 5D pop ebp004011B5 /. C2 0C00 retn 0C004011E0 >/> /55 push ebp004011E1 |. 8BEC mov ebp, esp004011E3 |. 83EC 40 sub esp, 40004011E6 |. 53 push ebx004011E7 |. 56 push esi004011E8 |. 57 push edi004011E9 |. 8D7D C0 lea edi, dword ptr [ebp-40]004011EC |. B9 10000000 mov ecx, 10004011F1 |. B8 CCCCCCCC mov eax, CCCCCCCC004011F6 |. F3:AB rep stos dword ptr es:[edi]004011F8 |. 837D 0C 01 cmp dword ptr [ebp+C], 1004011FC |. 75 0F jnz short 0040120D004011FE |. A1 BC9D4200 mov eax, dword ptr [g_dwData2]00401203 |. 83C0 01 add eax, 100401206 |. A3 BC9D4200 mov dword ptr [g_dwData2], eax0040120B |. EB 15 jmp short 004012220040120D |> 837D 0C 00 cmp dword ptr [ebp+C], 000401211 |. 75 0F jnz short 0040122200401213 |. 8B0D BC9D4200 mov ecx, dword ptr [g_dwData2]00401219 |. 83E9 01 sub ecx, 10040121C |. 890D BC9D4200 mov dword ptr [g_dwData2], ecx00401222 |> 5F pop edi00401223 |. 5E pop esi00401224 |. 5B pop ebx00401225 |. 8BE5 mov esp, ebp00401227 |. 5D pop ebp00401228 /. C2 0C00 retn 0C
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表