快速业务通道

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

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29
的情形。如果内层__try块的过滤器表达式不处理某个异常,那外层__try块的过滤器表达式就必须处理它。那现在要问,__except_handler3是如何知道SCOPETABLE数组的哪个元素相应于外层的__try块的呢?答案是:外层__try块的索引由 SCOPETABLE结构的previousTryLevel域给出。利用这种机制,你可以嵌套任意层的__try块。previousTryLevel 域就好像是一个函数中所有可能的异常处理程序构成的线性链表中的结点一样。如果trylevel的值为0xFFFFFFFF(实际上就是-1,这个值在 EXSUP.INC中被定义为TRYLEVEL_NONE),标志着这个链表结束。

回到__except_handler3的代码中。在获取了当前的trylevel之后,它就调用相应的SCOPETABLE结构中的过滤器表达式代码。如果过滤器表达式返回EXCEPTION_CONTINUE_SEARCH,__exception_handler3 移向SCOPETABLE数组中的下一个元素,这个元素的索引由previousTryLevel域给出。如果遍历完整个线性链表(还记得吗?这个链表是由于在一个函数内部嵌套使用__try块而形成的)都没有找到处理这个异常的代码,__except_handler3返回DISPOSITION_CONTINUE_SEARCH(原文如此,但根据_except_handler函数的定义,这个返回值应该为ExceptionContinueSearch。实际上这两个常量的值是一样的。我在伪代码中已经将其改正过来了),这导致系统移向下一个EXCEPTION_REGISTRATION帧(这个链表是由于函数嵌套调用而形成的)。

如果过滤器表达式返回EXCEPTION_EXECUTE_HANDLER,这意味着异常应该由相应的__except块处理。它同时也意味着所有前面的EXCEPTION_REGISTRATION帧都应该从链表中移除,并且相应的__except块都应该被执行。第一个任务通过调用__global_unwind2来完成的,后面我会讲到这个函数。跳过这中间的一些清理代码,流程离开__except_handler3转向__except块。令人奇怪的是,流程并不从__except块中返回,虽然是 __except_handler3使用CALL指令调用了它。

当前的trylevel值是如何被设置的呢?它实际上是由编译器隐含处理的。编译器非常机灵地修改这个扩展的EXCEPTION_REGISTRATION 结构中的trylevel域的值(实际上是生成修改这个域的值的代码)。如果你检查编译器为使用SEH的函数生成的汇编代码,就会在不同的地方都看到修改这个位于[EBP-04h]处的trylevel域的值的代码。

__except_handler3是如何做到既通过CALL指令调用__except块而又不让执行流程返回呢?由于CALL指令要向堆栈中压入了一个返回地址,你可以想象这有可能破坏堆栈。如果你检查一下编译器为__except块生成的代码,你会发现它做的第一件事就是将EXCEPTION_REGISTRATION结构下面8个字节处(即[EBP-18H]处)的一个DWORD值加载到ESP寄存器中(实际代码为MOV ESP,DWORD PTR [EBP-18H]),这个值是在函数的 prolog 代码中被保存在这个位置的(实际代码为MOV DWORD PTR [EBP-18H],ESP)。

ShowSEHFrames 程序

如果你现在觉得已经被EXCEPTION_REGISTRATION、scopetable、trylevel、过滤器表达式以及展开等等之类的词搞得晕头转向的话,那和我最初的感觉一样。但是编译器层面的结构化异常处理方面的知识并不适合一点一点的学。除非你从整体上理解它,否则有很多内容单独看并没有什么意义。当面对大堆的理论时,我最自然的做法就是写一些应用我学到的理论方面的程序。如果它能够按照预料的那样工作,我就知道我的理解(通常)是正确的。

下面是ShowSEHFrame.EXE的源代码。它使用__try/__except块设置了好几个 Visual C++ SEH 帧。然后它显示每一个帧以及Visual C++为每个帧创建的scopetable的相关信息。这个程序本身并不生成也不依赖任何异常。相反,我使用了多个__try块以强制Visual C++生成多个 EXCEPTION_REGISTRATION 帧以及相应的 scopetable。

//ShowSEHF

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站: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号