天天看點

反調試技術二

五、使用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");

       else

              return 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

       }

八、調用DeleteFiber函數

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

bool DeleteFiberApproach()

       char fib[1024] = {0};

       // 會抛出一個異常并被調試器捕獲

       DeleteFiber(fib);

       // 0x57的意思是ERROR_INVALID_PARAMETER

       return (GetLastError() != 0x57);

本文轉自 donjuan 部落格園部落格,原文連結:http://www.cnblogs.com/killmyday/archive/2011/05/31/2064171.html   ,如需轉載請自行聯系原作者

繼續閱讀