翻譯的很挫,大家不要介意。
原文:http://www.codeproject.com/KB/security/Intro_To_Win_Anti_Debug.aspx
介紹:
最近,逆向工程的工具已經是很豐富了。逆向工程是一個非常值得花時間投入的領域,現在很多關於這個領域的資來源站點點。在我學c++的同時學習逆向工程和組合語言真的協助了我理解代碼的工作,同時也提高了我c/c++和asm編寫的能力。然而,逆向工程也有不好的一面。破解者都是獨立使用他們自己逆向工程的知識來進行逆向別的程式員的代碼,常常解碼序號處理過程或者去除一個使用版的保護。一般,一個開發人員會保護自己成果,可以使用如Themida,Execryptor,Armadillo,甚至使用由Jim Charles開發的Eagle Protector保護系統。這邊文章將會探討一些獨特反調試技術,不會是包羅永珍,也不會探討複雜的用於商業上面得。
背景:
在你閱讀這邊文章之前,你應該非常熟悉ASM,電腦如何處理記憶體,Win32 調試API,至少應該對Windows內部有必要的知識。由於OS的差異,這裡的嗲嗎大多不能在*nix平台上使用。有關於逆向工程方面的知識,那就更好了。學習和實現反調試最大的事就是你也有開發你自己逆向技術,對於任何一個對逆向工程這個領域感興趣的人,是再好不過的了。另外一個要提到的就是,感興趣的讀者應該熟悉使用逆向工具,如OD,WindBG,IDA Pro,以及其他。下面是一些對於讀者非常有用的資訊的連結。
Windows Debugging API
Assembly Language
Computer Memory
IsDebuggerPresent:
這個可能是最簡單的調試保護的方法。這是Win32 調試API中的一個,你可以再MSDN中找到。
if(IsDebuggerPresent())
{
MessageBox(NULL, TEXT("Please close your debugging application" +
" and restart the program"),
TEXT("Debugger Found!"), 0);
ExitProcess(0);
}
// Normal Code Here....
使用PEB的IsDebuggerPresent:
IsDebuggerPresent函數其實是對這段代碼的封裝。這個是通過直接反問進程的PEB,讀取一個位元組的值,如果這個進程正處於調試狀態的話,那麼就會標示這個值。
char IsDbgPresent = 0;
__asm {
mov eax, fs:[30h]
mov al, [eax + 2h]
mov IsDbgPresent, al
}
if(IsDbgPresent)
{
MessageBox(NULL, TEXT("Please close your debugging " +
"application and restart the program"),
TEXT("Debugger Found!"), 0);
ExitProcess(0);
}
// Normal Execution
CheckRemoteDebuggerPresent:
這個也是Win32 調試API。這個可以檢測使用有遠程進程正在被調試。然而,我們也可以使用這個作為另一種方法來檢測我們自己的進程是否處於調試狀態。這個函數是通過使用將SYSTEM_INFORMATION_CLASS 設為7 (ProcessDebugPort)為參數調用NTDLL匯出的NtQueryInformationProcess完成的。可以參考MSDN參看說明:
BOOL IsDbgPresent = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &IsDbgPresent);
if(IsDbgPresent)
{
MessageBox(NULL, TEXT("Please close your debugging" +
" application and restart the program"),
TEXT("Debugger Found!"), 0);
ExitProcess(0);
}
// Normal Execution
NtQueryInformationProcess:
當然我們也可以不使用CheckRemoteDebuggerPresent,而是直接調用NtQueryInformationProcess來進行。MSDN並沒有鼓勵使用NTXxx函數,因為這些函數可能的行為可能會改變。因此,在提交使用這個函數之前需要考慮一些東西。
// Function Pointer Typedef for NtQueryInformationProcess
typedef unsigned long (__stdcall *pfnNtQueryInformationProcess)(IN HANDLE,
IN unsigned int, OUT PVOID, IN ULONG, OUT PULONG);
// ProcessDebugPort
const int ProcessDbgPort = 7;
// We have to import the function
pfnNtQueryInformationProcess NtQueryInfoProcess = NULL;
// Other Vars
unsigned long Ret;
unsigned long IsRemotePresent = 0;
HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));
if(hNtDll == NULL)
{
// Handle however.. chances of this failing
// is essentially 0 however since
// ntdll.dll is a vital system resource
}
NtQueryInfoProcess = (pfnNtQueryInformationProcess)
GetProcAddress(hNtDll, "NtQueryInformationProcess");
if(NtQueryInfoProcess == NULL)
{
// Handle however it fits your needs but as before,
// if this is missing there are some SERIOUS issues with the OS
}
// Time to finally make the call
Ret = NtQueryInfoProcess(GetCurrentProcess(), ProcessDbgPort,
&IsRemotePresent, sizeof(unsigned long), NULL);
if(Ret == 0x00000000 && IsRemotePresent != 0)
{
// Debugger is present
MessageBox(NULL, TEXT("Please close your debugging " +
"application and restart the program"),
TEXT("Debugger Found!"), 0);
ExitProcess(0);
}
NtGlobalFlag:
NtGlobalFlag在進程的PEB中是一個DWORD值。這個值包含有作業系統影響進程啟動並執行而設定的一些標誌位。當一個進程正處於調試狀態時,進程的標記會被設定為FLG_HEAP_ENABLE_TAIL_CHECK (0x10),FLG_HEAP_ENABLE_FREE_CHECK(0x20),FLG_HEAP_VALIDATE_PARAMETERS(0x40)。我們就可以使用這個來標示我們的進程是否處於被調試的狀態。
unsigned long NtGlobalFlags = 0;
__asm {
mov eax, fs:[30h]
mov eax, [eax + 68h]
mov NtGlobalFlags, eax
}
if(NtGlobalFlags & 0x70)
// 0x70 = FLG_HEAP_ENABLE_TAIL_CHECK |
// FLG_HEAP_ENABLE_FREE_CHECK |
// FLG_HEAP_VALIDATE_PARAMETERS
{
// Debugger is present
MessageBox(NULL, TEXT("Please close your debugging " +
"application and restart the program"),
TEXT("Debugger Found!"), 0);
ExitProcess(0);
}
// Normal execution