在上篇中,我們會為讀者介紹惡意軟件常用來的反仿真技術(shù)。本文中,我們將向讀者介紹惡意軟件用以阻礙對其進(jìn)行逆向工程的各種反調(diào)試技術(shù),以幫助讀者很好的理解這些技術(shù),從而能夠更有效地對惡意軟件進(jìn)行動態(tài)檢測和分析。
一、反調(diào)試技術(shù)
反調(diào)試技術(shù)是一種常見的反檢測技術(shù),因為惡意軟件總是企圖監(jiān)視自己的代碼以檢測是否自己正在被調(diào)試。為做到這一點,惡意軟件可以檢查自己代碼是否被設(shè)置了斷點,或者直接通過系統(tǒng)調(diào)用來檢測調(diào)試器。
1.斷點
為了檢測其代碼是否被設(shè)置斷點,惡意軟件可以查找指令操作碼0xcc(調(diào)試器會使用該指令在斷點處取得惡意軟件的控制權(quán)),它會引起一個SIGTRAP。如果惡意軟件代碼本身建立了一個單獨的處理程序的話,惡意軟件也可以設(shè)置偽斷點。用這種方法惡意軟件可以在被設(shè)置斷點的情況下繼續(xù)執(zhí)行其指令。
惡意軟件也可以設(shè)法覆蓋斷點,例如有的病毒采用了反向解密循環(huán)來覆蓋病毒中的斷點。相反,還有的病毒則使用漢明碼自我糾正自身的代碼。漢明碼使得程序可以檢測并修改錯誤,但是在這里卻使病毒能夠檢測并清除在它的代碼中的斷點。
2.計算校驗和
惡意軟件也可以計算自身的校驗和,如果校驗和發(fā)生變化,那么病毒會假定它正在被調(diào)試,并且其代碼內(nèi)部已被放置斷點。VAMPiRE是一款抗反調(diào)試工具,可用來逃避斷點的檢測。VaMPiRE通過在內(nèi)存中維護(hù)一張斷點表來達(dá)到目的,該表記錄已被設(shè)置的所有斷點。該程序由一個頁故障處理程序(PFH),一個通用保護(hù)故障處理程序(GPFH),一個單步處理程序和一個框架API組成。當(dāng)一個斷點被觸發(fā)的時候,控制權(quán)要么傳給PFH(處理設(shè)置在代碼、數(shù)據(jù)或者內(nèi)存映射I/O中的斷點),要么傳給GPFH(處理遺留的I/O斷點)。單步處理程序用于存放斷點,使斷點可以多次使用。
3.檢測調(diào)試器
在Linux系統(tǒng)上檢測調(diào)試器有一個簡單的方法,只要調(diào)用Ptrace即可,因為對于一個特定的進(jìn)程而言無法連續(xù)地調(diào)用Ptrace兩次以上。在Windows中,如果程序目前處于被調(diào)試狀態(tài)的話,系統(tǒng)調(diào)用isDebuggerPresent將返回1,否則返回0。這個系統(tǒng)調(diào)用簡單檢查一個標(biāo)志位,當(dāng)調(diào)試器正在運行時該標(biāo)志位被置1。直接通過進(jìn)程環(huán)境塊的第二個字節(jié)就可以完成這項檢查,以下代碼為大家展示的就是這種技術(shù):
mov eax, fs:[30h] move eax, byte [eax+2] test eax, eax jne @DdebuggerDetected |
在上面的代碼中,eax被設(shè)置為PEB(進(jìn)程環(huán)境塊),然后訪問PEB的第二個字節(jié),并將該字節(jié)的內(nèi)容移入eax。通過查看eax是否為零,即可完成這項檢測。如果為零,則不存在調(diào)試器;否則,說明存在一個調(diào)試器。
如果某個進(jìn)程為提前運行的調(diào)試器所創(chuàng)建的,那么系統(tǒng)就會給ntdll.dll中的堆操作例程設(shè)置某些標(biāo)志,這些標(biāo)志分別是FLG_HEAP_ENABLE_TAIL_CHECK、FLG_HEAP_ENABLE_FREE_CHECK和FLG_HEAP_VALIDATE_PARAMETERS。我們可以通過下列代碼來檢查這些標(biāo)志:
mov eax, fs:[30h] mov eax, [eax+68h] and eax, 0x70 test eax, eax jne @DebuggerDetected |
在上面的代碼中,我們還是訪問PEB,然后通過將PEB的地址加上偏移量68h到達(dá)堆操作例程所使用的這些標(biāo)志的起始位置,通過檢查這些標(biāo)志就能知道是否存在調(diào)試器。
檢查堆頭部內(nèi)諸如ForceFlags之類的標(biāo)志也能檢測是否有調(diào)試器在運行,如下所示:
mov eax, fs:[30h] mov eax, [eax+18h] ;process heap mov eax, [eax+10h] ;heap flags test eax, eax jne @DebuggerDetected |
上面的代碼向我們展示了如何通過PEB的偏移量來訪問進(jìn)程的堆及堆標(biāo)志,通過檢查這些內(nèi)容,我們就能知道Force標(biāo)志是否已經(jīng)被當(dāng)前運行的調(diào)試器提前設(shè)置為1了。
另一種檢測調(diào)試器的方法是,使用NtQueryInformationProcess這個系統(tǒng)調(diào)用。我們可以將ProcessInformationClass設(shè)為7來調(diào)用該函數(shù),這樣會引用ProcessDebugPort,如果該進(jìn)程正在被調(diào)試的話,該函數(shù)將返回-1。示例代碼如下所示。
|
在本例中,首先把NtQueryInformationProcess的參數(shù)壓入堆棧。這些參數(shù)介紹如下:第一個是句柄(在本例中是0),第二個是進(jìn)程信息的長度(在本例中為4字節(jié)),接下來是進(jìn)程信息類別(在本例中是7,表示ProcessDebugPort),下一個是一個變量,用于返回是否存在調(diào)試器的信息。如果該值為非零值,那么說明該進(jìn)程正運行在一個調(diào)試器下;否則,說明一切正常。最后一個參數(shù)是返回長度。使用這些參數(shù)調(diào)用NtQueryInformationProcess后的返回值位于isdebugged中。隨后測試該返回值是否為0即可。
另外,還有其他一些檢測調(diào)試器的方法,如檢查設(shè)備列表是否含有調(diào)試器的名稱,檢查是否存在用于調(diào)試器的注冊表鍵,以及通過掃描內(nèi)存以檢查其中是否含有調(diào)試器的代碼等。
另一種非常類似于EPO的方法是,通知PE加載器通過PE頭部中的線程局部存儲器(TLS)表項來引用程序的入口點。這會導(dǎo)致首先執(zhí)行TLS中的代碼,而不是先去讀取程序的入口點。因此,TLS在程序啟動就可以完成反調(diào)試所需檢測。從TLS啟動時,使得病毒得以能夠在調(diào)試器啟動之前就開始運行,因為一些調(diào)試器是在程序的主入口點處切入的。
| 共3頁: 1 [2] [3] 下一頁 | |||||
|


