日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

反调试技术揭秘(转)

發布時間:2024/7/23 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 反调试技术揭秘(转) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

?

在調試一些病毒程序的時候,可能會碰到一些反調試技術,也就是說,被調試的程序可以檢測到自己是否被調試器附加了,如果探知自己正在被調試,肯定是有人試圖反匯編之類的方法破解自己。為了了解如何破解反調試技術,首先我們來看看反調試技術。

?

?

?

一、Windows API 方法

?

Win32 提供了兩個 API,?IsDebuggerPresent 和 CheckRemoteDebuggerPresent 可以用來檢測當前進程是否正在被調試,以IsDebuggerPresent 函數為例,例子如下:

BOOL ret = IsDebuggerPresent();printf("ret = %d\n", ret);

破解方法很簡單,就是在系統里將這兩個函數 hook 掉,讓這兩個函數一直返回 false 就可以了,網上有很多做 hook API 工作的工具,也有很多工具源代碼是開放的,所以這里就不細談了。

?

?

?

二、查詢進程 PEB 的 BeingDebugged 標志位

?

當進程被調試器所附加的時候,操作系統會自動設置這個標志位,因此在程序里定期查詢這個標志位就可以了,例子如下:

bool PebIsDebuggedApproach() {char result = 0;__asm{// 進程的PEB地址放在fs這個寄存器位置上mov eax, fs:[30h]// 查詢BeingDebugged標志位mov al, BYTE PTR [eax + 2]?mov result, al}return result != 0; }

?

?

?

三、查詢進程 PEB 的 NtGlobal 標志位?

?

跟第二個方法一樣,當進程被調試的時候,操作系統除了修改 BeingDebugged 這個標志位以外,還會修改其他幾個地方,其中NtDll 中一些控制堆(Heap)操作的函數的標志位就會被修改,因此也可以查詢這個標志位,例子如下:

bool PebNtGlobalFlagsApproach() {int result = 0;__asm{// 進程的PEBmov eax, fs:[30h]// 控制堆操作函數的工作方式的標志位mov eax, [eax + 68h]// 操作系統會加上這些標志位FLG_HEAP_ENABLE_TAIL_CHECK,?// FLG_HEAP_ENABLE_FREE_CHECK and FLG_HEAP_VALIDATE_PARAMETERS,// 它們的并集就是x70//// 下面的代碼相當于C/C++的// eax = eax & 0x70and eax, 0x70mov result, eax}return result != 0;}


?

?

四、查詢 進程堆 的一些 標志位

?

這個方法是第三個方法的變種,只要進程被調試,進程在堆上分配的內存,在分配的堆的頭信息里,ForceFlags 這個標志位會被修改,因此可以通過判斷這個標志位的方式來反調試。因為進程可以有很多的堆,因此只要檢查任意一個堆的頭信息就可以了,所以這個方法貌似很強大,例子如下:

bool HeapFlagsApproach() {int result = 0;__asm{// 進程的PEBmov eax, fs:[30h]// 進程的堆,我們隨便訪問了一個堆,下面是默認的堆mov eax, [eax + 18h]// 檢查ForceFlag標志位,在沒有被調試的情況下應該是mov eax, [eax + 10h]mov result, eax}return result != 0; }

?

?

?

五、使用 NtQueryInformationProcess 函數

?

NtQueryInformationProcess 函數是一個未公開的 API,它的第二個參數可以用來查詢進程的調試端口。如果進程被調試,那么返回的端口值會是 -1,否則就是其他的值。由于這個函數是一個未公開的函數,因此需要使用 LoadLibrary 和 GetProceAddress的方法獲取調用地址,示例代碼如下:

// 聲明一個函數指針。typedef NTSTATUS (WINAPI *NtQueryInformationProcessPtr)(HANDLE processHandle,PROCESSINFOCLASS processInformationClass,PVOID processInformation,ULONG processInformationLength,PULONG returnLength);bool NtQueryInformationProcessApproach() {int debugPort = 0;HMODULE hModule = LoadLibrary(TEXT("Ntdll.dll "));NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hModule, "NtQueryInformationProcess");if ( NtQueryInformationProcess(GetCurrentProcess(), (PROCESSINFOCLASS)7, &debugPort, sizeof(debugPort), NULL) )printf("[ERROR NtQueryInformationProcessApproach] NtQueryInformationProcess failed\n");elsereturn debugPort == -1;return false;}

?

?

?

六、NtSetInformationThread 方法

?

這個也是使用 Windows 的一個未公開函數的方法,你可以在當前線程里調用 NtSetInformationThread,調用這個函數時,如果在第二個參數里指定 0x11 這個值(意思是 ThreadHideFromDebugger ),等于告訴操作系統,將所有附加的調試器統統取消掉。示例代碼:

// 聲明一個函數指針。typedef NTSTATUS (*NtSetInformationThreadPtr)(HANDLE threadHandle,THREADINFOCLASS threadInformationClass,PVOID threadInformation,ULONG threadInformationLength);void NtSetInformationThreadApproach() {HMODULE hModule = LoadLibrary(TEXT("ntdll.dll"));NtSetInformationThreadPtr NtSetInformationThread = (NtSetInformationThreadPtr)GetProcAddress(hModule, "NtSetInformationThread");NtSetInformationThread(GetCurrentThread(), (THREADINFOCLASS)0x11, 0, 0);}

?

?

?

七、觸發異常的方法

?

這個技術的原理是,首先,進程使用 SetUnhandledExceptionFilter 函數注冊一個未處理異常處理 函數A,如果進程沒有被調試的話,那么觸發一個未處理異常,會導致操作系統將控制權交給先前注冊的函數A;而如果進程被調試的話,那么這個未處理異常會被調試器捕捉,這樣我們的 函數A 就沒有機會運行了。

這里有一個技巧,就是觸發未處理異常的時候,如果跳轉回原來代碼繼續執行,而不是讓操作系統關閉進程。方案是在函數A里修改eip的值,因為在 函數A 的 參數 _EXCEPTION_POINTERS 里,會保存當時觸發異常的指令地址,所以在 函數A 里根據這個指令地址修改 寄存器eip 的值就可以了,示例代碼如下:

// 進程要注冊的未處理異常處理程序A LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *pei) {SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)pei->ContextRecord->Eax);// 修改寄存器eip的值pei->ContextRecord->Eip += 2;// 告訴操作系統,繼續執行進程剩余的指令(指令保存在eip里),而不是關閉進程return EXCEPTION_CONTINUE_EXECUTION; }bool UnhandledExceptionFilterApproach() {SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);__asm{// 將eax清零xor eax, eax// 觸發一個除零異常div eax}return false;}

?

?

?

八、調用 DeleteFiber 函數

?

如果給 DeleteFiber 函數傳遞一個無效的參數的話,DeleteFiber函數除了會拋出一個異常以外,還是將進程的LastError值設置為具體出錯原因的代號。然而,如果進程正在被調試的話,這個LastError值會被修改,因此如果調試器繞過了第七步里講的反調試技術的話,我們還可以通過驗證LastError值是不是被修改過來檢測調試器的存在,示例代碼:

bool DeleteFiberApproach() {char fib[1024] = {0};// 會拋出一個異常并被調試器捕獲DeleteFiber(fib);// 0x57的意思是ERROR_INVALID_PARAMETERreturn (GetLastError() != 0x57); }

?

?

?

總結

以上是生活随笔為你收集整理的反调试技术揭秘(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。