一、Windows 异常处理机制
- 交给调试器(进程必须被调试)
- 执行VEH 向量化异常处理(如果调试器不处理)
- 执行SEH 结构化异常处理(如果VEH不处理)
- TopLevelEH 顶层异常处理 (如果SEH不处理)(进程被调试时不会被执行)
- 交给调试器(上面的异常处理都说处理不了,就再次交给调试器)
- 调用异常端口通知csrss.exe
二、反调试:利用结构化异常处理(SEH)
- Windows提供了关键字__try 、 __except 进行SEH 结构化异常处理(而非C++的try、catch)。
- 如果程序正常运行未被调试,那么在__try中产生的异常将在__except模块中被处理。如果一个程序正在被调试,那么调试器会接管程序产生的异常,不会交给__except模块处理。根据这个思路,可以利用关键字__try 、 __except 判断程序是否处于调试器下。
- 系统提供了RaiseException 这个API用于手动抛出异常,第一个参数是要抛出的异常代码,其有效值如下:
STATUS_BREAKPOINT (0x80000003)
STATUS_SINGLE_STEP (0x80000004)
DBG_PRINTEXCEPTION_C (0x40010006)
DBG_RIPEXCEPTION (0x40010007)
DBG_CONTROL_C (0x40010005)
DBG_CONTROL_BREAK (0x40010008)
DBG_COMMAND_EXCEPTION (0x40010009)
ASSERTION_FAILURE (0xC0000420)
STATUS_GUARD_PAGE_VIOLATION (0x80000001)
SEGMENT_NOTIFICATION (0x40000005)
EXCEPTION_WX86_SINGLE_STEP (0x4000001E)
EXCEPTION_WX86_BREAKPOINT (0x4000001F)
- 反调试代码:
#include <iostream>
#include <Windows.h>
bool CheckDebugger() {
__try {
RaiseException(STATUS_BREAKPOINT, 0, 0, 0);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DWORD ExceptionCode = GetExceptionCode();
printf("not in debugging :利用__except模块进行结构化异常处理! \n");
printf("ExceptionCode = %08C \n", ExceptionCode);
return FALSE;
}
return TRUE;
}
int main()
{
bool res = CheckDebugger();
system("PAUSE");
}
三、反调试:利用顶层异常处理(UEF)
- TopLevelEH 全称顶层异常处理器(UEF),这个函数只能有一个,被保存在全局变量中。由于只会被系统默认的最底层 SEH 调用,所以又会被称作是 SEH 的一种,是整个异常处理的最后一环。所以通常都不会再此执行异常处理操作,而是进行内存 dump ,将消息发送给服务器,进行异常分析。
- 异常一旦被结构化异常处理(SEH )处理,就不会再传递给顶层异常处理器(UEF)。
LONG WINAPI MyTopLevelExceptionHandle(PEXCEPTION_POINTERS ExceptionInfo)
{
printf("ExceptionCode: %X\n", ExceptionInfo->ExceptionRecord->ExceptionCode);
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
{
ExceptionInfo->ContextRecord->Eax = 6;
ExceptionInfo->ContextRecord->Ecx = 2;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_EXECUTE_HANDLER;
}
int main()
{
SetUnhandledExceptionFilter(MyTopLevelExceptionHandle);
int number = 6;
number /= 0;
printf("number = %d \n", number);
system("PAUSE");
}
参考资料