為了保護自己的程式不被破譯等,很多軟體使用了反調試技術來阻止逆向程式員對自己程式進行爆破,這同時也催生了另一種技術--反調試破解技術的出現。反調試技術分為靜态反調試技術和動态反調試技術。相比來說靜态反調試技術更容易實作,破解一般也隻需要一次,我們這次就先談一下靜态反調試技術,以及對應的破解之道。
1.PEB結構中有幾個重要的成員标示了程序是否處于被調試狀态。(以下以32位為例) +0x002 BeingDebugged : UChar +0x00c Ldr : _PEB_LDR_DATA +0x018 ProcessHeap : Ptr32 Void +0x068 NtGlobalFlag : Uint4B
BeingDebugged成員在被調試狀态會顯示1,正常情況下為0。解決方法:更改該值為0。 Ldr:程序在被調試狀态時堆記憶體區域會出現一些特殊的标志,未使用的堆記憶體區域全部填充着0xFEEEFEEE,而Ldr正好在堆記憶體中被建立(隻在XP系統中有,Vista之後的系統沒有這種标志)。解決方法:将該區域覆寫為NULL即可。 ProcessHeap:ProcessHeap.Flags(+0x00c)在正常情況下值為0x2,ProcessHeap.ForceFlags成員(+0x10)的值為0x0,當調試時,該值會改變。(隻在XP中有效)。解決辦法:隻需将值改回去即可。 NtGlobalFalg:PEB.NtGlobalFlag會在調試情況下顯示0x70,該值是以下Flags值or運算的結果:(附加到程序無效,隻有啟動調試有效) FLG_HEAP_ENABLE_TAIL_CHECK (0x10) FLG_HEAP_ENABLE_FREE_CHECK (0x20) FLG_HEAP_VALIDATE_PARAMETERS (0x40) 解決方法:重置0即可 2.NtQueryInformationProcess()可以查詢ProcessDebugPort(0x7),ProcessDebugObjectHandle(0x1E)ProcessDebugFlags(0x1F) 當程序處于調試狀态時,系統會給它配置設定一個調試端口(Debug Port),正常狀态dwDebugPort為,調試狀态為0xFFFFFFFF 當程序處于調試狀态時,ProcessDebugObjectHandle一個句柄值,正常狀态為NULL 當程序處于調試狀态時,ProcessDebugFlags為0,正常為1 3.NtQueryObject()函數可以枚舉系統所有對象,通過觀察系統是否有調試對象句柄,就可以知道是否有程序在被調試。(wcscmp(L"DebugObject",pObjectTypeInfo->TypeName.Buffer)==0),解決方法,改變該函數參數 4.ZwSetInformationThread()該函數顧名思義是給線程設定資訊的。該函數有兩個參數,第一個參數ThreadHandle為線程句柄,第二參數ThreadInformationClass表示線程資訊類型,其值設定為ThreadHideFromDebugger(0x11),調用該函數後,調試程序将會與調試器分離開來,使調試器終止調試,同時終止自身程序。該函數對正常運作程式沒有影響。 6.TLS(線程局部存儲)TLS函數代碼一般先于main()函數執行,于是我們可以在這裡進行對程式是否被調試的判斷,例如判斷是否被下了int3斷點,PEB中的BeingDebugged是否為1等。相關具體問題可以看我另一篇關于TLS的博文。 7.ETC利用API獲得程序視窗,程序,計算機名稱,虛拟機是否在運作狀态等判斷運作環境是否安全。