2种基于异常机制的反调试方法

63 篇文章 4 订阅
    如题,一种是利用异常处理例程进行反调试:首先安装好一个异常处理例程,然后人为抛出异常在异常处理例程中通过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

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值