快速业务通道

Win32结构化异常处理(SEH)探秘(上)

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29
这两个函数的使用范围了。)

MOV EAX,DWORD PTR [EBP-14] ; 执行完毕,EAX指向EXCEPTION_POINTERS结构
MOV EAX,DWORD PTR [EAX] ; 执行完毕,EAX指向EXCEPTION_RECORD结构
MOV EAX,DWORD PTR [EAX] ; 执行完毕,EAX中是ExceptionCode的值

现在回到扩展的 EXCEPTION_REGISTRATION 结构上来。在这个结构开始前的8个字节处(即[EBP-18H]处),Visual C++ 保留了一个DWORD来保存所有prolog代码执行完毕之后的堆栈指针(ESP)的值(实际生成的指令为MOV DWORD PTR [EBP-18H],ESP)。这个DWORD中保存的值是函数执行时ESP寄存器的正常值(除了在准备调用其它函数时把参数压入堆栈这个过程会改变 ESP寄存器的值并在函数返回时恢复它的值外,函数在执行过程中一般不改变ESP寄存器的值)。

看起来好像我一下子给你灌输了太多的信息,我承认。在继续下去之前,让我们先暂停,来回顾一下 Visual C++ 为使用结构化异常处理的函数生成的标准异常堆栈帧,它看起来像下面这个样子:

EBP-00 _ebp
EBP-04 trylevel
EBP-08 scopetable数组指针
EBP-0C handler函数地址
EBP-10指向前一个EXCEPTION_REGISTRATION结构
EBP-14 GetExceptionInformation
EBP-18 栈帧中的标准ESP

在操作系统看来,只存在组成原始 EXCEPTION_REGISTRATION 结构的两个域:即[EBP-10h]处的prev指针和[EBP-0Ch]处的handler函数指针。栈帧中的其它所有内容是针对于Visual C++的。把这个Visual C++生成的标准异常堆栈帧记到脑子里之后,让我们来看一下真正实现编译器层面SEH的这个Visual C++运行时库例程——__except_handler3。

__except_handler3 和 scopetable

我真的很希望让你看一看Visual C++运行时库源代码,让你自己好好研究一下__except_handler3函数,但是我办不到。因为 Microsoft并没有提供。在这里你就将就着看一下我为__except_handler3函数写的伪代码吧:。

图九 __except_handler3函数的伪代码:

int __except_handler3(
struct _EXCEPTION_RECORD * pExceptionRecord,
struct EXCEPTION_REGISTRATION * pRegistrationFrame,
struct _CONTEXT *pContextRecord,
void * pDispatcherContext )
{
LONG filterFuncRet;
LONG trylevel;
EXCEPTION_POINTERS exceptPtrs;
PSCOPETABLE pScopeTable;
CLD // 将方向标志复位(不测试任何条件!)
// 如果没有设置EXCEPTION_UNWINDING标志或EXCEPTION_EXIT_UNWIND标志
// 表明这是第一次调用这个处理程序(也就是说,并非处于异常展开阶段)
if ( ! (pExceptionRecord->ExceptionFlags
& (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) )
{
// 在堆栈上创建一个EXCEPTION_POINTERS结构
exceptPtrs.ExceptionRecord = pExceptionRecord;
exceptPtrs.ContextRecord = pContextRecord;
// 把前面定义的EXCEPTION_POINTERS结构的地址放在比
// establisher栈帧低4个字节的位置上。参考前面我讲
// 的编译器为GetExceptionInformation生成的汇编代
// 码*(PDWORD)((PBYTE)pRegistrationFrame - 4) = &exceptPtrs;
// 获取初始的“trylevel”值
trylevel = pRegistrationFrame->trylevel;
// 获取指向scopetable数组的指针
scopeTable = pRegistrationFrame->scopetable;
search_for_handler:
if ( pRegistrationFrame->trylevel != TRYLEVEL_NONE )
{
if ( pRegistrationFrame->scopetable[trylevel].lpfnFilter )
{
PUSH EBP // 保存这个栈帧指针
// !!!非常重要!!!切换回原来的EBP。正是这个操作才使得
// 栈帧上的所有局部变量能够在异常发生后仍然保持它的值不变。
EBP = &pR

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号