調(diào)試與反調(diào)試系列丨跑的比main快的反調(diào)試

作者:小阿栗
首先要了解“進(jìn)程—線程”的關(guān)系
進(jìn)程:可以理解為一個內(nèi)存塊,是一塊虛擬內(nèi)存。在3環(huán)(應(yīng)用層)的結(jié)構(gòu)是PEB,在內(nèi)核的結(jié)構(gòu)是EPROCESS。
線程:在CPU上根據(jù)時間片進(jìn)行搶占切換,是為進(jìn)程工作的。在3環(huán)(應(yīng)用層)的結(jié)構(gòu)是TEB,在內(nèi)核的結(jié)構(gòu)是ETHREAD。
進(jìn)程本身沒有任何執(zhí)行能力,只是通過結(jié)構(gòu)來描述。進(jìn)程創(chuàng)建的時候,一定會有一個主線程運(yùn)行。運(yùn)行多線程有很多子線程,子線程的生命周期是由主線程決定的。
今天要講的反調(diào)試是TLS(線程局部存儲):可以簡單理解為一個線程的CALLBACK。
一般情況:
進(jìn)程創(chuàng)建->主線程運(yùn)行代碼
如果程序里存在TLS(線程局部存儲):
進(jìn)程創(chuàng)建->主線程創(chuàng)建->執(zhí)行TLS回調(diào)函數(shù)->主線程運(yùn)行代碼
我們先來創(chuàng)建一個DLL項(xiàng)目。步驟如下:
1.選擇新建項(xiàng)目

2.創(chuàng)建win32控制臺應(yīng)用程序->點(diǎn)擊確定

3.勾選空項(xiàng)目,完成

4.新建源文件entry.cpp

5.配置
5.1?選擇屬性

5.2修改運(yùn)行庫,應(yīng)用

6.添加#include、#include

7.向鏈接器聲明,要使用TLS

8.復(fù)制PIMAGE_TLS_CALLBACK里的三個參數(shù)

9.完成注冊TLS函數(shù)的回調(diào)

10.重新生成->運(yùn)行

發(fā)現(xiàn)沒有運(yùn)行到main函數(shù)
11.加斷點(diǎn),再運(yùn)行

發(fā)現(xiàn)還是運(yùn)行不起來.但是直接運(yùn)行,可以正常打印,正常停止

12.試下其他調(diào)試器
12.1在od里運(yùn)行:

發(fā)現(xiàn)不能進(jìn)入主模塊
12.2在IDA里打開:

Ida會自動停在main函數(shù)上,意味著靜態(tài)調(diào)試也發(fā)現(xiàn)不了TLS
動態(tài)調(diào)試沒進(jìn)入主模塊,靜態(tài)調(diào)試看不到。想找到TLS需要先了解一個原理,Windows下可執(zhí)行文件都是PE文件(包含exe、dll、sys、com等)
PE結(jié)構(gòu)里->數(shù)據(jù)目錄表(常見的導(dǎo)出表、導(dǎo)入表等)->TLS表
所以,加入TLS_CALLBACK,在TLS表里會找到TLS回調(diào)函數(shù),這是找到TLS回調(diào)的一個方法,但是常規(guī)方法找不到TLS回調(diào)函數(shù)。