本期作者/牛杰
前言
反調(diào)試技術(shù),是一種防止逆向的方案。逆向人員如果遇到復雜的代碼混淆,有時會使用調(diào)試器動態(tài)分析代碼邏輯簡化分析流程。例如惡意軟件通常會被安全研究人員、反病毒廠商和其他安全專業(yè)人員分析和調(diào)試,以了解其行為和功能,并開發(fā)相應的安全措施來保護系統(tǒng),這時,惡意軟件開發(fā)人員就會使用反調(diào)試技術(shù)阻礙逆向人員的分析,以達到增加自己惡意代碼的存活時間。此外,安全人員也需要了解反調(diào)試技術(shù),當遇到反調(diào)試代碼時,可以使用相對應的反反調(diào)試。
反調(diào)試
1. IsDebuggerPresent
IsDebuggerPresent 用于檢測當前進程是否正在被調(diào)試。該函數(shù)屬于 Windows 調(diào)試輔助功能,可以幫助開發(fā)人員在程序運行過程中進行調(diào)試。
IsDebuggerPresent 函數(shù)的原型如下:
BOOL IsDebuggerPresent(void);
該函數(shù)返回一個布爾值,如果當前進程正在被調(diào)試,則返回 TRUE;否則返回 FALSE。
檢查進程環(huán)境塊(PEB)中是否設置了正在調(diào)試的標志。
這實際上與IsDebuggerPresent()內(nèi)部執(zhí)行的代碼相同。
x86的PEB指針從DWORD FS:[0x30]中獲取,x64在QWORD GS:[0x60]中獲取。
IsDebuggerPresent 函數(shù)只能檢測當前進程是否正在被調(diào)試,而不能檢測其他進程的調(diào)試狀態(tài)。此外,安全研究人員和反病毒廠商可以使用各種技術(shù)和工具來繞過 IsDebuggerPresent 函數(shù)的檢測,因此它并不是一個絕對可靠的方法來判斷系統(tǒng)是否正在進行調(diào)試。
2. CheckRemoteDebuggerPresent
CheckRemoteDebuggerPresent 用于檢測當前進程是否被遠程調(diào)試器附加。該函數(shù)可以檢測當前進程是否正在被遠程調(diào)試器(如遠程調(diào)試器工具或調(diào)試代理程序)監(jiān)視和調(diào)試,惡意軟件可以使用該函數(shù)來判斷自身是否處于被遠程調(diào)試的環(huán)境中,并根據(jù)檢測結(jié)果采取相應的措施,如崩潰、隱藏關(guān)鍵代碼等,以防止被分析和調(diào)試。
CheckRemoteDebuggerPresent 函數(shù)的原型如下:
BOOL CheckRemoteDebuggerPresent( HANDLE hProcess, PBOOL pbDebuggerPresent );
該函數(shù)接受兩個參數(shù):
hProcess:要檢查的進程的句柄。通常使用 GetCurrentProcess() 函數(shù)獲取當前進程的句柄。
pbDebuggerPresent:一個指向 BOOL 類型的變量的指針,用于接收檢測結(jié)果。如果檢測到遠程調(diào)試器附加,則該變量被設置為 TRUE;否則設置為 FALSE。
3. 斷點檢測
斷點是一種調(diào)試技術(shù),用于在特定的內(nèi)存地址上設置斷點,以便在程序執(zhí)行到該地址時觸發(fā)中斷,因此可以通過判斷斷點的存在與否來確認程序是否被調(diào)試,斷點分為硬件斷點與軟件斷點,檢測的方式不同。
硬件斷點檢測
x86架構(gòu),DR0到DR3寄存器用于設置硬件斷點的地址,DR4和DR5寄存器在x86架構(gòu)中沒有特定的用途,DR6寄存器是一個狀態(tài)寄存器,用于指示硬件斷點的觸發(fā)情況。因此我們需要判斷DR0-DR3的值,如果有值不為0,則處于調(diào)試狀態(tài),x64架構(gòu)引入了新的調(diào)試寄存器,稱為DR7寄存器,用于控制硬件斷點和其他調(diào)試功能,但是判斷是否被調(diào)試的方式與x86架構(gòu)相同。獲取值的代碼如下:
BOOL HardwareBreakpoints() { BOOL bResult = FALSE; PCONTEXT ctx = PCONTEXT(VirtualAlloc(NULL, sizeof(CONTEXT), MEM_COMMIT, PAGE_READWRITE)); if(ctx) { SecureZeroMemory(ctx, sizeof(CONTEXT)); ctx->ContextFlags = CONTEXT_DEBUG_REGISTERS; if(GetThreadContext(GetCurrentThread(), ctx)) { if(ctx->Dr0 != 0|| ctx->Dr1 != 0|| ctx->Dr2 != 0|| ctx->Dr3 != 0) bResult = TRUE; } VirtualFree(ctx, 0, MEM_RELEASE); } returnbResult; }
軟件斷點檢測
軟件斷點又稱int3,在IA-32指令集中用操作碼CC (0xCC)表示,因此有時軟件點的檢測也稱為"0xCC"檢測,調(diào)試器在對應設置斷點的位置上修改該地址的字節(jié)為0xCC。若是關(guān)鍵位置檢測到該指令,可以判斷進程處于調(diào)試狀態(tài)。
4. PEB
在Windows操作系統(tǒng)中,PEB(Process Environment Block)是一個數(shù)據(jù)結(jié)構(gòu),它存儲了進程的環(huán)境信息和狀態(tài)。每個運行的進程都有一個獨立的PEB。
1. BeingDebugged
與IsDebuggerPresent()內(nèi)部執(zhí)行的代碼相同,獲取方式如下:
//x86 PPEB pPeb = (PPEB)__readfsdword(0x30); //x64 PPEB pPeb = (PPEB)__readgsqword(0x60);
2. NtGlobalFlag
NtGlobalFlag 是PEB的一個字段,通常,當進程未被調(diào)試時,NtGlobalFlag字段包含值0x0。調(diào)試進程時,該字段通常包含值0x70。
該字段在x86越x64架構(gòu)中的位置不同。
x86在PEB偏移0x68的位置,x64在PEB便0xBC的位置。
Windows內(nèi)核全局標記,在Windows調(diào)試方案中經(jīng)常用到。這個標記定義了一組系統(tǒng)的調(diào)試參數(shù),包括啟用或禁用調(diào)試技術(shù)的開關(guān)、造成崩潰的錯誤代碼和處理方式等等。通過改變這個標記,可以在運行時設置和禁用不同的調(diào)試技術(shù)和錯誤處理方式,比如調(diào)試器只能訪問當前進程、只允許用戶模式調(diào)試、啟用特定的錯誤處理方式等等。但由于NtGlobalFlag標記是內(nèi)核全局標記,其改變會影響整個系統(tǒng)的行為,需要謹慎處理。
5.ProcessHeap
通過PEB偏移0x18可以找到ProcessHeap,結(jié)構(gòu)體如下:
struct _PEB32 { UCHAR InheritedAddressSpace; //0x0 UCHAR ReadImageFileExecOptions; //0x1 UCHAR BeingDebugged; //0x2 union { UCHAR BitField; //0x3 struct { UCHAR ImageUsesLargePages:1; //0x3 UCHAR IsProtectedProcess:1; //0x3 UCHAR IsImageDynamicallyRelocated:1; //0x3 UCHAR SkipPatchingUser32Forwarders:1; //0x3 UCHAR IsPackagedProcess:1; //0x3 UCHAR IsAppContainer:1; //0x3 UCHAR IsProtectedProcessLight:1; //0x3 UCHAR IsLongPathAwareProcess:1; //0x3 }; }; ULONG Mutant; //0x4 ULONG ImageBaseAddress; //0x8 ULONG Ldr; //0xc ULONG ProcessParameters; //0x10 ULONG SubSystemData; //0x14 ULONG ProcessHeap; //0x18 .... }
在ProcessHeap加上偏移可以找到HeapFlags與ForceFlags,偏移的值根據(jù)系統(tǒng)版本和位數(shù)會有變化,如下表:
HeapFlags
ForceFlags
如果HeapFlags的值大于2,或ForceFlags的值大于0時,說明被調(diào)試。
6. INT 2D
int 2d反調(diào)試原理很簡單,正常運行時int 2d觸發(fā)異常,進入程序的異常處理函數(shù)。而當調(diào)試運行時,OD會處理該異常,將eip+1繼續(xù)運行,因此可以在異常處理函數(shù)中添加一些操作,如果沒有執(zhí)行這些代碼,說明被調(diào)試。這種只能檢測原版Ollydbg,x64dbg和一些帶有反檢測插件的調(diào)試器無效。
7. 進程列表
一般情況下,主進程在主線程中啟動核心代碼
QueryInformationJobObject這個api可以獲取當前程序所有的進程列表
不論是主進程還是主線程,他們的ImageFileName應該是都是源程序的文件名filename.exe
8. NtQueryInformationProcess
NtQueryInformationProcess原型如下:
NTSTATUS NTAPI NtQueryInformationProcess( HANDLE ProcessHandle,// 進程句柄 PROCESSINFOCLASS ProcessInformationClass,// 檢索的進程信息類型 PVOID ProcessInformation,// 接收進程信息的緩沖區(qū)指針 ULONG ProcessInformationLength,// 緩沖區(qū)指針大小 PULONG ReturnLength // 實際接收的進程信息大小 );
PROCESSINFOCLASS原型如下:
typedefenum_PROCESSINFOCLASS { ProcessBasicInformation, ProcessQuotaLimits, ProcessIoCounters, ProcessVmCounters, ProcessTimes, ProcessBasePriority, ProcessRaisePriority, ProcessDebugPort, //0x7 ProcessExceptionPort, ProcessAccessToken, ProcessLdtInformation, ProcessLdtSize, ProcessDefaultHardErrorMode, ProcessIoPortHandlers, ProcessPooledUsageAndLimits, ProcessWorkingSetWatch, ProcessUserModeIOPL, ProcessEnableAlignmentFaultFixup, ProcessPriorityClass, ProcessWx86Information, ProcessHandleCount, ProcessAffinityMask, ProcessPriorityBoost, ProcessDeviceMap, ProcessSessionInformation, ProcessForegroundInformation, ProcessWow64Information, ProcessImageFileName, ProcessLUIDDeviceMapsEnabled, ProcessBreakOnTermination, ProcessDebugObjectHandle, // 0x1E ProcessDebugFlags, // 0x1F ProcessHandleTracing, ProcessIoPriority, ProcessExecuteFlags, ProcessResourceManagement, ProcessCookie, ProcessImageInformation, ProcessCycleTime, ProcessPagePriority, ProcessInstrumentationCallback, ProcessThreadStackAllocation, ProcessWorkingSetWatchEx, ProcessImageFileNameWin32, ProcessImageFileMapping, ProcessAffinityUpdateMode, ProcessMemoryAllocationMode, ProcessGroupInformation, ProcessTokenVirtualizationEnabled, ProcessConsoleHostProcess, ProcessWindowInformation, ProcessHandleInformation, ProcessMitigationPolicy, ProcessDynamicFunctionTableInformation, ProcessHandleCheckingMode, ProcessKeepAliveCount, ProcessRevokeFileHandles, ProcessWorkingSetControl, ProcessHandleTable, ProcessCheckStackExtentsMode, ProcessCommandLineInformation, ProcessProtectionInformation, ProcessMemoryExhaustion, ProcessFaultInformation, ProcessTelemetryIdInformation, ProcessCommitReleaseInformation, ProcessDefaultCpuSetsInformation, ProcessAllowedCpuSetsInformation, ProcessSubsystemProcess, ProcessJobMemoryInformation, ProcessInPrivate, ProcessRaiseUMExceptionOnInvalidHandleClose, ProcessIumChallengeResponse, ProcessChildProcessInformation, ProcessHighGraphicsPriorityInformation, ProcessSubsystemInformation, ProcessEnergyValues, ProcessActivityThrottleState, ProcessActivityThrottlePolicy, ProcessWin32kSyscallFilterInformation, ProcessDisableSystemAllowedCpuSets, ProcessWakeInformation, ProcessEnergyTrackingState, ProcessManageWritesToExecutableMemory,REDSTONE3 ProcessCaptureTrustletLiveDump, ProcessTelemetryCoverage, ProcessEnclaveInformation, ProcessEnableReadWriteVmLogging, ProcessUptimeInformation, ProcessImageSection, ProcessDebugAuthInformation, ProcessSystemResourceManagement, ProcessSequenceNumber, ProcessLoaderDetour, ProcessSecurityDomainInformation, ProcessCombineSecurityDomainsInformation, ProcessEnableLogging, ProcessLeapSecondInformation, ProcessFiberShadowStackAllocation, ProcessFreeFiberShadowStackAllocation, MaxProcessInfoClass } PROCESSINFOCLASS;
1. ProcessDbgPort
該方式是CheckRemoteDebuggerPresent的另一種調(diào)用方式。
通過NTDLL導出NtQueryInformationProcess函數(shù),PROCESSINFOCLASS設置為7,該值是進程調(diào)試端口(ProcessDebugPort),該值不為0說明被調(diào)試。
2. ProcessDebugObjectHandle
通過NTDLL導出NtQueryInformationProcess函數(shù),PROCESSINFOCLASS設置為0x1E,該值是進程的調(diào)試對象句柄(ProcessDebugObjectHandle),當該值存在且函數(shù)返回值不為NULL,說明進程處于調(diào)試狀態(tài),當返回值為NULL,或該值不存在,說明處于非調(diào)試狀態(tài)。
3. ProcessDebugFlags
通過NTDLL導出NtQueryInformationProcess函數(shù),PROCESSINFOCLASS設置為0x1f,該值獲取了EPROCESS中的成員NoDebugInherit,該值為0說明被調(diào)試。
9. WUDFPlatform.dll模塊
WUDFPlatform.dll模塊中,有三個導出函數(shù) WudfIsAnyDebuggerPresent,WudfIsKernelDebuggerPresent,WudfIsUserDebuggerPresent,分別為任何調(diào)試器、0環(huán)調(diào)試器和3環(huán)調(diào)試器,該模塊只有x64。
通過調(diào)用這三個函數(shù),如果返回值不為0,則正在被調(diào)試。
代碼如下:
HMODULE h_wudf = LoadLibrary(L"WUDFPlatform.dll"); if(h_wudf == NULL) { cout << "fail"?<< endl; ????} ????// WudfIsAnyDebuggerPresent ????pWudfIsAnyDebuggerPresent WudfIsAnyDebuggerPresent = (pWudfIsAnyDebuggerPresent)GetProcAddress(h_wudf, "WudfIsAnyDebuggerPresent"); ????if?(WudfIsAnyDebuggerPresent == NULL) { ????????cout << "未發(fā)現(xiàn)調(diào)試器"?<< endl; ????} ????if?(WudfIsAnyDebuggerPresent() != 0) { ????????cout << "發(fā)現(xiàn)調(diào)試器"?<< endl; ????} ????// WudfIsKernelDebuggerPresent ????pWudfIsKernelDebuggerPresent WudfIsKernelDebuggerPresent = (pWudfIsKernelDebuggerPresent)GetProcAddress(h_wudf, "WudfIsKernelDebuggerPresent"); ????if?(WudfIsKernelDebuggerPresent == NULL) { ????????cout << "未發(fā)現(xiàn)3環(huán)調(diào)試器"" << endl; ????} ????if (WudfIsKernelDebuggerPresent() != 0) { ????????cout << "發(fā)現(xiàn)0環(huán)調(diào)試器" << endl; ????} ????// pWudfIsUserDebuggerPresent ????pWudfIsUserDebuggerPresent WudfIsUserDebuggerPresent = (pWudfIsUserDebuggerPresent)GetProcAddress(h_wudf, "WudfIsUserDebuggerPresent"); ????if (WudfIsUserDebuggerPresent == NULL) { ????????cout << "未發(fā)現(xiàn)3環(huán)調(diào)試器" << endl; ????} ????if (WudfIsUserDebuggerPresent() != 0) { ????????cout << "發(fā)現(xiàn)3環(huán)調(diào)試器" << endl;
測試結(jié)果如下
總結(jié)
本篇介紹了部分反調(diào)試的方法,在自己的代碼中使用反調(diào)試技術(shù),可以增加逆向人員的分析難度,或是通過了解這些技術(shù)的原理,在分析惡意代碼時進行反反調(diào)試,在后續(xù)的文章中,將會介紹更多的反調(diào)試方法。
-
WINDOWS
+關(guān)注
關(guān)注
4文章
3614瀏覽量
91444 -
調(diào)試
+關(guān)注
關(guān)注
7文章
612瀏覽量
34748 -
調(diào)試技術(shù)
+關(guān)注
關(guān)注
0文章
7瀏覽量
6722 -
代碼
+關(guān)注
關(guān)注
30文章
4900瀏覽量
70790 -
調(diào)試器
+關(guān)注
關(guān)注
1文章
313瀏覽量
24334
原文標題:反調(diào)試技術(shù)-上
文章出處:【微信號:蛇矛實驗室,微信公眾號:蛇矛實驗室】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
介紹6種常見的反調(diào)試方法

動態(tài)反調(diào)試技術(shù)總結(jié)
shell編程的簡單命令語句了解
學PLC技術(shù)超簡單
labview怎么調(diào)試?基于labview的USB調(diào)試教程案例分析
何為調(diào)試,調(diào)試為何?
STM32調(diào)試DEBUG時需要了解那些知識相關(guān)資料概述

如何使用Xilinx SDK創(chuàng)建Linux應用程序,并進行開發(fā)和調(diào)試
本田唱反調(diào),混動車型仍然是重點
220kv電力變壓器正反調(diào)和粗細調(diào)沖擊電壓分析

基于OpenOCD和GDB的簡單且廉價的步進調(diào)試器

FPGA在線調(diào)試的方法簡單總結(jié)

評論