Win32结构化异常处理(SEH)探秘(上)
2010-10-15 09:07:37 来源:Web开发网一旦系统找到一个处理该异常的某个回调函数,它就停止遍历结构链表。
下面的代码 MYSEH2.CPP 就是一个异常处理函数不处理某个异常的例子。为了使代码尽量简单,我使用了编译器层面的异常处理。main 函数只设置了一个 __try/__except块。在__try 块内部调用了 HomeGrownFrame 函数。这个函数与前面的 MYSEH 程序非常相似。它也是在堆栈上创建一个 EXCEPTION_REGISTRATION 结构,并且让 FS:[0] 指向此结构。在建立了新的异常处理程序之后,这个函数通过向一个 NULL 指针所指向的内存处写入数据而故意引发一个错误:
*(PDWORD)0 = 0;
这个异常处理回调函数,同样被称为_except_handler,却与前面的那个截然不同。它首先打印出 ExceptionRecord 结构中的异常代码和标志,这个结构的地址是作为一个指针参数被这个函数接收的。打印出异常标志的原因稍后就会明白。因为_except_handler 函数并没有打算修复出错的代码,因此它返回 ExceptionContinueSearch。这导致操作系统继续在 EXCEPTION_REGISTRATION 结构链表中搜索下一个 EXCEPTION_REGISTRATION结构。接下来安装的异常回调函数是针对 main 函数中的__try/__except块的。__except 块简单地打印出“Caught the exception in main()”。此时我们只是简单地忽略这个异常来表明我们已经处理了它。 以下是 MYSEH2.CPP:
//=================================================
// MYSEH2 - Matt Pietrek 1997
// Microsoft Systems Journal, January 1997
// FILE: MYSEH2.CPp
// 使用命令行CL MYSEH2.CPP编译
//=================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
EXCEPTION_DISPOSITION
__cdecl _except_handler(
struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext )
{
printf( "Home Grown handler: Exception Code: %08X Exception Flags %X",
ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionFlags );
if ( ExceptionRecord->ExceptionFlags & 1 )
printf( " EH_NONCONTINUABLE" );
if ( ExceptionRecord->ExceptionFlags & 2 )
printf( " EH_UNWINDING" );
if ( ExceptionRecord->ExceptionFlags & 4 )
printf( " EH_EXIT_UNWIND" );
if ( ExceptionRecord->ExceptionFlags & 8 )
// 注意这个标志
printf( " EH_STACK_INVALID" );
if ( ExceptionRecord->ExceptionFlags & 0x10 ) // 注意这个标志
printf( " EH_NESTED_CALL" );
printf( "n" );
// 我们不想处理这个异常,让其它函数处理吧
return ExceptionContinueSearch;
}
void HomeGrownFrame( void )
{
DWORD handler = (DWORD)_except_handler;
__asm
{
// 创建EXCEPTION_REGISTRATION结构:
push handler
// handler函数的地址
push FS:[0] // 前一个handler函数的地址
mov FS:[0],ESp
// 安装新的EXECEPTION_REGISTRATION结构
}
*(PDWORD)0 = 0;
// 写入地址0,从而引发一个错误
printf( "I should never get here!n" );
__asm
{
// 移去我们的EXECEPTION_REGISTRATION结构
mov eax,[ESP]
// 获取前一个结构
mov FS:[0], EAX
// 安装前一个结构
add esp, 8 // 把我们EXECEPTION_REGISTRATION结构弹出堆栈
}
}
int main()
{
__try
{
HomeGrownFrame();
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
printf( "Caught the exception in main()n" );
}
return 0;
}
更多精彩
赞助商链接