本期作者/牛杰
前言
是一種防止逆向的方案。逆向人員如果遇到復雜的代碼混淆,有時會使用調試器動態分析代碼邏輯簡化分析流程。例如惡意軟件通常會被安全研究人員、反病毒廠商和其他安全專業人員分析和調試,以了解其行為和功能,并開發相應的安全措施來保護系統,這時,惡意軟件開發人員就會使用反調試技術阻礙逆向人員的分析,以達到增加自己惡意代碼的存活時間。此外,安全人員也需要了解反調試技術,當遇到反調試代碼時,可以使用相對應的反反調試。在反調試技術上中,我們介紹了9種常見的反調試方法,本篇繼續介紹6種方式。
反調試
NtSetInformationThread 是 Windows 操作系統提供的一個函數,用于設置線程的信息,該函數通常用來設置線程的優先級,此外通過設置不同的 ThreadInformationClass 參數,可以實現隱藏線程、禁止調試、設置調試狀態等操作,從而增加程序的安全性和防御性,該函數原型與枚舉信息如下。
__kernel_entry NTSYSCALLAPI NTSTATUS NtSetInformationThread( [in] HANDLE ThreadHandle, [in] THREADINFOCLASS ThreadInformationClass, [in] PVOID ThreadInformation, [in] ULONG ThreadInformationLength ); typedef enum_THREADINFOCLASS { ThreadBasicInformation, ThreadTimes, ThreadPriority, ThreadBasePriority, ThreadAffinityMask, ThreadImpersonationToken, ThreadDescriptorTableEntry, ThreadEnableAlignmentFaultFixup, ThreadEventPair_Reusable, ThreadQuerySetWin32StartAddress, ThreadZeroTlsCell, ThreadPerformanceCount, ThreadAmILastThread, ThreadIdealProcessor, ThreadPriorityBoost, ThreadSetTlsArrayAddress, ThreadIsIoPending, ThreadHideFromDebugger, ThreadBreakOnTermination, MaxThreadInfoClass } THREADINFOCLASS;
NtSetInformationThread通過ThreadInformationClass中ThreadHideFromDebugger來反調試 是 NtSetInformationThread 函數的一個參數,用于將當前線程隱藏起來,使得調試器無法對其進行調試。這個參數的作用是防止調試器附加到被隱藏的線程上進行調試操作。
當線程被隱藏后,調試器無法訪問和控制該線程的執行。這可以用作一種反調試技術,防止惡意用戶或惡意軟件使用調試器來分析、修改或干擾程序的執行。
通過隱藏線程,程序可以增加自身的安全性,防止被調試器進行逆向工程、代碼分析、內存調試等操作。這對于一些需要保護知識產權、防止惡意調試的應用程序或安全軟件來說特別有用。
NtSetInformationThread反調試demo如下。
#include#include typedefenum_THREADINFOCLASS { ThreadBasicInformation, ThreadTimes, ThreadPriority, ThreadBasePriority, ThreadAffinityMask, ThreadImpersonationToken, ThreadDescriptorTableEntry, ThreadEnableAlignmentFaultFixup, ThreadEventPair_Reusable, ThreadQuerySetWin32StartAddress, ThreadZeroTlsCell, ThreadPerformanceCount, ThreadAmILastThread, ThreadIdealProcessor, ThreadPriorityBoost, ThreadSetTlsArrayAddress, ThreadIsIoPending, ThreadHideFromDebugger, ThreadBreakOnTermination, MaxThreadInfoClass } THREADINFOCLASS; typedefNTSTATUS(WINAPI* pNtSetInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG); voidHideFromDebugger(){ HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll")); pNtSetInformationThread NtSetInformationThread = (pNtSetInformationThread)GetProcAddress(hNtDll, "NtSetInformationThread"); NTSTATUS status = NtSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0); } voidThreadHid(){ HideFromDebugger(); intx = 1; while(1) { printf("%d",x); Sleep(1000); x++; }; } intmain() { CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ThreadHid, 0, 0, 0); getchar(); return0; }
使用調試器執調試該程序,可以看到程序正常執行。
然后在線程中下斷點,程序會自動關閉。
需要注意的是,雖然使用 ThreadHideFromDebugger 可以增加程序的安全性,但它并不是絕對的安全措施,因為仍然存在其他方法可以繞過或檢測到線程隱藏。因此,在設計安全應用程序時,應綜合考慮多種防護措施,并定期進行安全評估和更新。
2.SeDebugPrivilege
默認情況下,進程沒有調試權限(SeDebugPrivilege),除非自己主動開啟,但是調試器啟動程序并調試時,會從調試器繼承該權限。使用該方式需要先調用CsrGetProcessId獲取csrss.exe的pid,該函數在ntdll。獲取pid后,通過OpenProcess讀取句柄csrss.exe,如果能獲取則說明被調試,代碼如下。
HMODULEhMod = LoadLibrary(TEXT("ntdll.dll")); typedefint(*CSRGETPROCESSID)(); CSRGETPROCESSIDCsrGetProcessId = (CSRGETPROCESSID)GetProcAddress(hMod, "CsrGetProcessId"); DWORDpid = CsrGetProcessId(); HANDLEhandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); if(handle) { returntrue; } else{ returnfalse; }
3.時間檢測
通過計算時間差,如果時間間隔過長,判斷當前進程被反調試,常用API有API有:QueryPerformanceCounter、GetTickCount、GetSystemTime、GetLocalTime,這些API使用方法相似,我們使用GetTickCount舉例。
DWORDstarttime = GetTickCount(); DWORDendtime = GetTickCount(); if(endtime - starttime > 500) { returntrue; } else{ returnfalse; }
4.父進程
通過檢測自身父進程來判定是否被調試,原理非常簡單,我們的系統在運行程序的時候,絕大多數應用程序都是由explorer.exe這個父進程派生而來的子進程,也就是說如果沒有被調試其得到的父進程就是explorer.exe的進程PID,而如果被調試則該進程的父進程PID就會變成調試器的PID值,通過對父進程的檢測即可實現檢測是否被調試的功能。
#include#include #include intIsDebug() { DWORD ExplorerId = 0; PROCESSENTRY32 pe32 = { 0}; DWORD ProcessId = GetCurrentProcessId(); GetWindowThreadProcessId(FindWindow(L"Progman", NULL), &ExplorerId); HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if(hProcessSnap != INVALID_HANDLE_VALUE) { pe32.dwSize = sizeof(PROCESSENTRY32); Process32First(hProcessSnap, &pe32); do { if(ProcessId == pe32.th32ProcessID) { // 判斷父進程是否是 Explorer.exe if(pe32.th32ParentProcessID != ExplorerId) { returnTRUE; } } } while(Process32Next(hProcessSnap, &pe32)); } returnFALSE; } intmain(intargc, char* argv[]) { if(IsDebug()) { printf("正在被調試 "); } system("pause"); return0; }
5.NtYieldExecution
NtYieldExecution讓當前線程主動放棄其剩余的時間片,并執行下一個等待的線程。如果沒有線程被安排執行或在使用調試器單步調試時線程無法切換,NtYieldExecution函數返回為STATUS_NO_YIELD_PERFORMED (0x40000024)。
#defineSTATUS_NO_YIELD_PERFORMED 0x40000024 typedefNTSTATUS(WINAPI* pNtYieldExecution)(); boolisDebug() { HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll")); pNtYieldExecution NtYieldExecution = (pNtYieldExecution)GetProcAddress(hNtDll, "NtSetInformationThread"); INT iDebugged = 0; for(inti = 0; i < 0x20; i++) ????{ ????????Sleep(0xf); ????????if?(NtYieldExecution() != STATUS_NO_YIELD_PERFORMED) ????????????iDebugged++; ????} ????if?(iDebugged <= 3) ????????return?false; ????else ????????return?true; ????system("pause"); }
但是這種方法其實并不可靠,因為它只顯示當前進程中是否有一個高優先級的線程。然而,它可以作為一種反跟蹤技術。
6.DbgUiRemoteBreakin
DbgUiRemoteBreakin打補丁可以反OD附加調試,當我們用OD附加調試時,CreateRemoteThread函數在目標程序中創建了一個遠程線程,然后在遠程線程中調用DbgUiRemoteBreakin函數,DbgUiRemoteBreakin內部調用了DbgBreakPoint函數,DbgBreakPoint函數內部下了一個int 3斷點,觸發異常讓操作系統運行異常處理程序,然后操作系統把控制權交管給調試器,因此可以創建TLS回調的方式hook DbgUiRemoteBreakin,內部直接調用ExitProcess()退出程序,測試代碼如下。
# include# include # include intmain(intargc, char* argv[]) { BYTE bBuffer[0x10] = { 0}; DWORD dwBreakAddress; DWORD dwOldProtect; DWORD dwNum; dwBreakAddress = (DWORD)GetProcAddress(LoadLibrary(L"ntdll.dll"), "DbgUiRemoteBreakin"); bBuffer[0] = 0xE9; *((DWORD*)(bBuffer + 1)) = (DWORD)ExitProcess - dwBreakAddress; VirtualProtect((LPVOID)dwBreakAddress, 0x10, PAGE_EXECUTE_READWRITE, &dwOldProtect); WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwBreakAddress, bBuffer, 5, &dwNum); VirtualProtect((LPVOID)dwBreakAddress, 0x10, dwOldProtect, &dwOldProtect); while(1) { staticintx = 0; printf("%d ",x); Sleep(1000); x++; } return0; }
當OD附加,程序終止。
總結
本篇繼續介紹了其他反調試的方法,在自己的代碼中使用反調試技術,可以增加逆向人員的分析難度,或是通過了解這些技術的原理,在分析惡意代碼時進行反反調試,在后續的文章中,將會介紹更多的反調試方法。
-
WINDOWS
+關注
關注
4文章
3570瀏覽量
89308 -
操作系統
+關注
關注
37文章
6896瀏覽量
123751 -
調試
+關注
關注
7文章
589瀏覽量
34064 -
函數
+關注
關注
3文章
4346瀏覽量
62977
原文標題:反調試技術-下
文章出處:【微信號:蛇矛實驗室,微信公眾號:蛇矛實驗室】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論