Windows 反调试介绍






4.81/5 (38投票s)
Windows Anti-Debugging 技术简要介绍。
引言
近年来,用于逆向工程的工具如雨后春笋般涌现。对于那些对此领域感兴趣的人来说,有很多资源网站,而且这个领域非常值得投入时间。我发现学习 C++ 的同时接触逆向工程和汇编语言,极大地帮助我理解代码的工作原理,并同时提升了我的 C/C++ 和 ASM 编码能力。然而,逆向工程也有其阴暗的一面。Cracker 是那些利用逆向工程知识来逆向他人代码的人,通常是为了解码序列号的处理方式,或者移除试用版的保护。理所当然,开发者会希望保护他们的投资;这可以通过工具实现,例如 Themida、Execryptor、Armadillo,甚至是由 CodeProject resident Jim Charles 编写的一个名为 Eagle Protector 的保护系统。本文旨在向个人介绍一些反调试技术,并不打算涵盖所有内容,也不涉及商业保护器使用的一些更复杂的例程。
背景
阅读本文的读者应扎实掌握 ASM、计算机内存处理、Win32 调试 API,并至少了解一些 Windows 内部知识。由于操作系统的根本差异,这些代码在任何 *nix 平台上的运行可能性不大。在逆向工程领域拥有任何其他知识也将是加分项。学习和实现反调试的一个好处是,你也能提高你的逆向能力,这对于任何对该领域感兴趣的人来说都是一个巨大的优势。除了前面提到的主题,感兴趣的读者还应该熟悉用于二进制应用程序逆向的工具,如 OllyDBG、WinDBG、SoftICE、IDA Pro 等。以下是一些在阅读正文之前读者应熟悉的重点信息链接:
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 函数;它可以用于检查远程进程是否正在被调试。然而,我们也可以将其作为检查自身进程是否被调试的另一种方法。对于想知道此函数如何不同的读者来说,CheckRemoteDebuggerPresent
调用 NTDLL 的导出函数 NtQueryInformationProcess
,并将 SYSTEM_INFORMATION_CLASS
设置为 7(ProcessDebugPort
)。该函数的 MSDN 参考可在以下网址找到: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
一个人也可以直接调用 NtQueryInformationProcess
而不是调用 CheckRemoteDebuggerPresent
。MSDN 不鼓励使用任何 NtxXx 函数,因为其行为可能会发生改变,因此在决定使用该函数之前可能需要仔细考虑。该函数的 MSDN 参考可在以下网址找到:MSDN。
// 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
关注点
Windows 中还有更多反调试技术,一些方法,如使用 CloseHandle
或 OutputDebugStringA
,在 Windows Vista 中已被修补,因此未包含在本文中。我计划撰写其他关于其他反调试技术的文章,许多可用的方法仅凭内联汇编很难实现,需要使用其他 ASM 风格/编译器来更有效地实现。
参考文献
- www.securityfocus.com - 很棒的网站,我最初就是在这里找到许多这些技术的。
历史
- 2008 年 9 月 18 日 - 原始修订。