翻译的很挫,大家不要介意。
原文: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