Win32结构化异常处理(SEH)探秘(上)
egistrationFrame->_ebp; // 调用过滤器函数 filterFuncRet = scopetable[trylevel].lpfnFilter(); POP EBP // 恢复异常处理程序的栈帧指针 if ( filterFuncRet != EXCEPTION_CONTINUE_SEARCH ) { if ( filterFuncRet < 0 ) // EXCEPTION_CONTINUE_EXECUTION return ExceptionContinueExecution; // 如果能够执行到这里,说明返回值为EXCEPTION_EXECUTE_HANDLEr scopetable = pRegistrationFrame->scopetable; // 让操作系统清理已经注册的栈帧,这会使本函数被递归调用 __global_unwind2( pRegistrationFrame ); // 一旦执行到这里,除最后一个栈帧外,所有的栈帧已经 // 被清理完毕,流程要从最后一个栈帧继续执行 EBP = &pRegistrationFrame->_ebp; __local_unwind2( pRegistrationFrame, trylevel ); // NLG = "non-local-goto" (setjmp/longjmp stuff) __NLG_Notify( 1 ); // EAX = scopetable->lpfnHandler // 把当前的trylevel设置成当找到一个异常处理程序时 // SCOPETABLE中当前正在被使用的那一个元素的内容 pRegistrationFrame->trylevel = scopetable->previousTryLevel; // 调用__except {}块,这个调用并不会返回 pRegistrationFrame->scopetable[trylevel].lpfnHandler(); } } scopeTable = pRegistrationFrame->scopetable; trylevel = scopeTable->previousTryLevel; goto search_for_handler; } else // trylevel == TRYLEVEL_NONE { return ExceptionContinueSearch; } } else // 设置了EXCEPTION_UNWINDING标志或EXCEPTION_EXIT_UNWIND标志 { PUSH EBP // 保存EBp EBP = &pRegistrationFrame->_ebp; // 为调用__local_unwind2设置EBp __local_unwind2( pRegistrationFrame, TRYLEVEL_NONE ) POP EBP // 恢复EBp return ExceptionContinueSearch; } } 虽然__except_handler3的代码看起来很多,但是记住一点:它只是一个我在文章开头讲过的异常处理回调函数。它同MYSEH.EXE和 MYSEH2.EXE中的异常回调函数都带有同样的四个参数。__except_handler3大体上可以由第一个if语句分为两部分。这是由于这个函数可以在两种情况下被调用,一次是正常调用,另一次是在展开阶段。其中大部分是在非展开阶段的回调。 __except_handler3一开始就在堆栈上创建了一个EXCEPTION_POINTERS结构,并用它的两个参数来对这个结构进行初始化。我在伪代码中把这个结构称为 exceptPrts,它的地址被放在[EBP-14h]处。你回忆一下前面我讲的编译器为 GetExceptionInformation和 GetExceptionCode 函数生成的汇编代码就会意识到,这实际上初始化了这两个函数使用的指针。 接着,__except_handler3从EXCEPTION_REGISTRATION帧中获取当前的trylevel(在[EBP-04h]处)。 trylevel变量实际是scopetable数组的索引,而正是这个数组才使得一个函数中的多个__try块和嵌套的__try块能够仅使用一个 EXCEPTION_REGISTRATION结构。每个scopetable元素结构如下:
SCOPETABLE结构中的第二个成员和第三个成员比较容易理解。它们分别是过滤器表达式代码的地址和相应的__except块的地址。但是prviousTryLevel成员有点复杂。总之一句话,它用于嵌套的__try块。这里的关键是函数中的每个__try块都有一个相应的SCOPETABLE结构。 正如我前面所说,当前的 trylevel 指定了要使用的scopetable数组的哪一个元素,最终也就是指定了过滤器表达式和__except块的地址。现在想像一下两个__try块嵌套 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |