五、使用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 ,如需轉載請自行聯系原作者