如题,一种是利用异常处理例程进行反调试:首先安装好一个异常处理例程,然后人为抛出异常在异常处理例程中通过IsDebuggerPresent来判断程序是否被调试;另一种是利用未处理异常进行反跟踪,其原理是:当异常发生时所有异常处理例程都不能处理异常,系统线程异常处理例程将起作用,它调用 ZwQueryInformationProcess 判断是否被调试,
如果没有调试并且程序中调用SetUnhandledExceptionFilter安装了最后异常处理例程的话,系统转向对它的调用。
第一种方法中IsDebuggerPresent是通过返回FS寄存器上记录的地址的一些偏移量来实现的。在debugger中可以任意操作当前进程内存地址上的值,所以只需要用调试器把[[FS:30]:2的值修改成0,IsDebuggerPresent就会返回false,导致判断失败。相比第二种方法中UnhandledExceptionFilter是否调用取决于系统内核的判断。用户态的调试器要想改变这个行为就得颇费功夫了。下面我将依次展示两种反调试方法。
第一种方法,通过在异常处理例程中判断IsDebuggerPresent的返回值:
#include <windows.h>
int AntiDebugInSEH(EXCEPTION_POINTERS* ExceptionInfo)
{
DWORD state = 0x00;
__asm
{
mov eax,dword ptr fs:[30h];
movzx eax, byte ptr ds:[eax+2h];
mov state,eax;
}
ExceptionInfo->ContextRecord->Eax = state;
ExceptionInfo->ContextRecord->Eip = 0x06+(DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress;
return EXCEPTION_CONTINUE_EXECUTION;
}
int main()
{
int i=0;
__try
{
__asm
{
xor eax,eax;
mov dword ptr [eax],0; //触发异常
}
__asm
{
//异常返回后,eax的值为AntiDebugInSEH中ExceptionInfo->ContextRecord->Eax设定的值
mov i,eax
}
if(i==1)
{}
else
{
MessageBox(NULL,"","",0);
}
i++;
}
__except(AntiDebugInSEH(GetExceptionInformation()))
{
}
}
上面这段代码,如果正常运行将弹出对话框,如果调试运行对话框是看不到了。文章中也提到了,可以通过修改[[fs:30]:2]处的内存地址使IsDebuggerPresent失效,好的,祭出windbg:
进入异常时,[fs:[30h]:2]处的值为0x0001,即正在调试状态:
0:000> r eax
eax=7ffd5000
0:000> dd eax
7ffd5000 00010000 ffffffff 00400000 76fb8880
7ffd5010 00291940 00000000 00290000 76fb8380
为了使IsDebuggerPresent失效,修改0x7ffd5000处的内存值:
0:000> ed 7ffd5000 0x00000000
0:000> dd eax
7ffd5000 00000000 ffffffff 00400000 76fb8880
7ffd5010 00291940 00000000 00290000 76fb8380
当程序从异常处理例程返回时,又可以见到对话框了:
接下来看下第二种反调试方法:
#include <windows.h>
LONG WINAPI UnhandledExcept(EXCEPTION_POINTERS *pExpInfo)
{
if(pExpInfo->ExceptionRecord->ExceptionCode != EXCEPTION_BREAKPOINT)
{
return EXCEPTION_EXECUTE_HANDLER;
}
else
{
pExpInfo->ContextRecord->Eip = (DWORD)(pExpInfo->ContextRecord->Eip+1);
pExpInfo->ContextRecord->Eax = 0x0000FEEE;
return EXCEPTION_CONTINUE_EXECUTION;
}
}
int main()
{
HMODULE hMod = LoadLibrary("kernel32.dll");
DWORD* funcAddr = (DWORD*)GetProcAddress(hMod,"ExitProcess");
SetUnhandledExceptionFilter(UnhandledExcept);
_asm int 3;
__asm
{
cmp ax,0xFEEE;
jz next;
push 0;
mov eax,funcAddr;
call eax;
next:
}
{
MessageBox(NULL,"","",MB_OK);
}
}
这段代码,还是读者自己试下,我暂时没想到如果绕过检测的方法。
参考连接:
http://www.52pojie.cn/forum.php?mod=viewthread&tid=16609
http://bbs.pediy.com/showthread.php?t=9023