SEH链和展开操作


每次我们定义了一个新的SEH异常处理回调函数,EXCEPTION_REGISTRATION结构的prev字段都被要求填写上一个EXCEPTION_REGISTRATION结构的地址,随着应用程序对模块的调用一层层深入下去的时候,那么最后回调函数会形成一个SEH链

 

当程序中有多个线程在运行的时候,每个线程中都会存在各自的SEH链,这些SEH链中指定了多个回调函数,除他们以外,系统中可能还会存在一个全局性的筛选器,再者如果进程被调试,调试器进程也相当于一个异常处理的程序存在.那么当一个异常发生的时候,系统究竟该听谁的呢?

 

在这种情况下,系统按一定的步骤选择一个回调函数并执行他,如果这个回调函数可以执行这个异常,那么其他的回调函数都不会执行,否则系统执行下一个回调函数

(1).系统查看产生异常的进程是否正在被调试,如果正在被调试的话,那么向调试器发送EXCEPTION_DEBUG_EVENT事件

(2).如果进程没有被调试或者调试器不去处理这个异常,那么系统 检查异常所处的线程,并在这个线程环境中查看fs:[0]来确定是否安装有SEH异常处理回调函数,如果有则调用它.

(3).回调函数尝试处理这个异常,如果可以正确处理的话,则修正错误并将返回值设置为ExceptionContinueExecution,这时系统将结束整个查找过程

(4).如果回调函数返回ExceptionContinueSearch,告知系统他无法处理这个异常,那么系统将根据SEH链中的prev字段得到上一个回调函数地址,并重复步骤(3)过程,直到链中某个回调函数返回ExceptionContinueExecution为止,查找结束 

(5).如果到了SEH链的尾部,却没有一个回调函数愿意处理这个异常,那么系统将再次检测进程是否正在被调试,如果被调试的话,则再次通知调试器

(6).如果调试器还是不去处理这个异常或者进程没有被调试 ,那么系统检查有没有安装筛选器回调函数,如果有,则去调用他,筛选器回调函数返回的时候,系统默认的异常处理程序根据这个返回值将做出相应的动作

(7).如果没有安装筛选器回调函数,系统直接 调用默认的异常处理程序终止进程

一个 比较形象的比喻就是:

Windows拿着一份异常处理的活挨个问每个回调函数
"你干不干" ,"不干","你呢","我也不干"... ... 当问到某一个的时候,
他说:"那我来干好了!"那么Windows就不会在去问其他人了,于是相安无事

有时,问完一圈后,谁都不愿意干(当然是干不了)Windows大怒:"谁都不干,看我炒了你们!"于是就把整个进程终止掉,所有的异常处理回调函数全部完蛋啦
(筛选器-全局的-进程的  SEH-线程的)

 完整的异常处理回调函数

<span style="font-family:Microsoft YaHei;font-size:13px;">_Handler1	proc	C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext;C调用方式-调用者自己平衡堆栈.if	(异常代码 == 0c0000027h) || (异常标志 & EXCEPTION_UNWINDING) || (异常标志 & EXCEPTION_UNWINDING_FOR_EXIT);进行资源释放等扫尾工作mov	eax,ExceptionContinueSearch.elseif 异常代码 == 可以处理的异常代码;处理异常,对CONTEXT进行修正;进行展开操作mov	eax,ExceptionContinueExecution.else;其他无法处理的异常代码mov eax,ExceptionContinueSearch.endifret_Handler1	endp</span>


 

二.展开操作(Unwinding)

如果把第一个SEH处理的函数的返回值改成ExceptionContinueSearch这个时候函数将会进行循环查找

这个时候回调函数应该进行一些扫尾工作,因为其将被卸载

注册 Unwinding操作可以使用RtlUnwinding函数

invoke RtlUnwinding,lpLastStackFrame,lpCodeLabel,lpExceptionRecord,dwRet

(1).lpLastStackFrame:这个参数设置为NULL,那么他将对所有的SEH链进行展开操作,这时所有的回调函数参数中的异常标志在带有EXCEPTION_UNWINDING的同时也带有EXCEPTION_UNWINDING_FOR_EXIT标志位,这种方式称为展开退出

指定为当前回调函数的EXCEPTION_REGISTRATION结构的地址的话,表示对当前回调函数之后的所有其他回调函数进行展开操作,这样RtlUnwinding函数调用的每一个回调函数时,异常标记位都会带有EXCEPTION_UNWINDING标记位

(2).lpCodeLabel参数指明函数将要返回的位置,如果位NULL,那么RtlUnwinding函数将返回到其后面的一条指令,否则函数直接返回到lpCodeLabel指定的位置

(3).lpExceptionRecord指定一个EXCEPTION_RECORD结构,这个结构将在调用的时候传给每一个回调函数

(4).dwRet参数一般不被使用,它可以指明为NULL

 

使用RtlUnwinding函数时要注意的是:这个函数并不像其他API函数一样保存esi,edi和ebx寄存器的值,在函数返回时候这些寄存器的值可能会改变,所以如果程序用到这些寄存器的话,必须手动去保存和恢复他们

 

 

<span style="font-family:Microsoft YaHei;font-size:13px;">		.386.model flat,stdcalloption casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include		windows.inc
include		user32.inc
includelib	user32.lib
include		kernel32.inc
includelib	kernel32.libL macro var:VARARGLOCAL @lbl.const@lbl db var,0.codeexitm <offset @lbl>
endm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.data
szMsg1		db	'这是外层异常处理程序(将处理异常)',0dh,0ahdb	'异常发生位置:%08X,异常代码:%08X,标志:%08X',0
szMsg2		db	'这是内层异常处理程序(对异常不进行处理)',0dh,0ahdb	'异常发生位置:%08X,异常代码:%08X,标志:%08X',0
szCaption	db	'提示信息',0
szBeforeUnwind	db	'现在将开始 Unwind,当前的 FS:[0] = %08X',0
szAfterUnwind	db	'Unwind 返回,当前的 FS:[0] = %08X',0
szSafe1		db	'回到了外层子程序的安全位置!',0
szSafe2		db	'回到了内层子程序的安全位置!',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 外层错误 Handler,将处理异常
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler1	proc	C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContextlocal	@szBuffer[256]:bytepushadmov	esi,_lpExceptionRecordmov	edi,_lpContextassume	esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT,fs:nothinginvoke	wsprintf,addr @szBuffer,addr szMsg1,\[edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlagsinvoke	MessageBox,NULL,addr @szBuffer,NULL,MB_OK
;********************************************************************
; 将 EIP 指向安全的位置并恢复堆栈
;********************************************************************mov	eax,_lpSEHpush	[eax + 8]pop	[edi].regEippush	_lpSEHpop	[edi].regEsp
;********************************************************************
; 对前面的 Handler 进行 Unwind 操作
;********************************************************************invoke	wsprintf,addr @szBuffer,addr szBeforeUnwind,dword ptr fs:[0]invoke	MessageBox,NULL,addr @szBuffer,addr szCaption,MB_OKinvoke	RtlUnwind,_lpSEH,NULL,NULL,NULLinvoke	wsprintf,addr @szBuffer,addr szAfterUnwind,dword ptr fs:[0]invoke	MessageBox,NULL,addr @szBuffer,addr szCaption,MB_OK
;********************************************************************assume	esi:nothing,edi:nothingpopadmov	eax,ExceptionContinueExecutionret_Handler1	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 内层错误 Handler,不处理异常
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler2	proc	C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContextlocal	@szBuffer[256]:bytepushadmov	esi,_lpExceptionRecordmov	edi,_lpContextassume	esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXTinvoke	wsprintf,addr @szBuffer,addr szMsg2,\[edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlagsinvoke	MessageBox,NULL,addr @szBuffer,NULL,MB_OKassume	esi:nothing,edi:nothingpopadmov	eax,ExceptionContinueSearchret_Handler2	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Test2		procassume	fs:nothingpush	offset _SafePlacepush	offset _Handler2push	fs:[0]mov	fs:[0],esp
;********************************************************************
; 会引发异常的指令
;********************************************************************pushadxor	eax,eaxmov	dword ptr [eax],0popad		;这一句将无法被执行
_SafePlace:invoke	MessageBox,NULL,L("回到了内层子程序的安全位置!"),L("提示信息"),MB_OKpop	fs:[0]add	esp,8ret_Test2		endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Test1		procassume	fs:nothingpush	offset _SafePlacepush	offset _Handler1push	fs:[0]mov	fs:[0],espinvoke	_Test2
_SafePlace:invoke	MessageBox,NULL,L("回到了外层子程序的安全位置!"),L("提示信息"),MB_OKpop	fs:[0]add	esp,8ret_Test1		endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:invoke	_Test1invoke	ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>end	start
</span>

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/375307.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring的基本知识

首先是回顾一下spring的基本知识 1、controller 控制器&#xff08;注入服务&#xff09; 2、service 服务&#xff08;注入dao&#xff09; 3、repository dao&#xff08;实现dao访问&#xff09; 4、component &#xff08;把普通pojo实例化到spring容器中&#xff0c;相当于…

vs2010 EF4.0 访问mysql

需要安装mysql-connector-net-6.3.5 6.8.9的安装完后在dbfirst里找不到对应的提供程序 链接字符串里需要 指定下编码(如果不是gbk的话) <add name"sourceEntities" connectionString"metadatares://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;pr…

Win32ASM 变长参数的理解

C语言里面 提供了一些宏 可以使用变长参数 int MsgPrintf(INT dwszBuffer,TCHAR* szCaption,TCHAR* szFormat,...){LPVOID lpszBuffer;va_list pArgList;va_start(pArgList,szFormat);lpszBuffer HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,100);_vsntprintf((LPTSTR)lpsz…

jquery判断一个div的边界是否超出另外一个div的边界

摘要&#xff1a;本文简单介绍jquery判断一个div的边界是否超出另外一个div的边界&#xff0c;如果超出边界做出相应的处理。 1、实现效果 判断前 判断后 2、实现思路 实现类似的判断&#xff0c;主要是获取两个div在浏览器中的上下左右的四至&#xff0c;在jquery中&#xff0…

Gson解析Json格式数据

//数据定义&#xff1a;class User{ String name; String password; String getName(){}void setName(){}}Gson gsonnew Gson(); ////解析一条json数据&#xff1a;令str为[{"name":"21001","password":"21001"}] User usernew User()…

进程的细节

从今天开始,重新学习一些细节性质的东西 一.在VS开发环境中,应用程序的入口点: _tWinMain WinMainCRTStartup _tWinMain wWinMainCRTStartup _tmain mainCRTStartup _tmain wmainCRTStartup 相关的介…

maven环境快速搭建(转)

最近&#xff0c;开发中要用到maven&#xff0c;所以对maven进行了简单的学习。因为有个maven高手在身边&#xff0c;所以&#xff0c;很快就上手了&#xff0c;我这里算是自我总结吧。关于maven是什么东东&#xff0c;请参考其它文章。 ----------------准备工作-------------…

cocos2d-x3.0 相对布局(一)

2dx相对布局和Android非常类似。假设前完成Android它应该是easy入门。Size widgetSize Director::getInstance()->getWinSize();Text* alert Text::create("Layout", "fonts/Marker Felt.ttf", 30 );alert->setColor(Color3B(159, 168, 176));aler…

管理员以标准权限运行时

在XP时代,大多数用户都用一个管理员(administrator)帐号来登录Windows 利用这个账户,用户几乎能没有任何限制的访问重要的系统资源,因为该账户被授予了很高的权限,一旦用这个帐号登录了xp以及xp之前的操作系统,Windows操作系统就会创建一个安全令牌(security token).每当有代码…

HDU 4791 amp; ZOJ 3726 Alice#39;s Print Service (数学 打表)

题目链接&#xff1a; HDU:http://acm.hdu.edu.cn/showproblem.php?pid4791 ZJU:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId5072 Problem DescriptionAlice is providing print service, while the pricing doesnt seem to be reasonable, so people using…

夺命雷公狗---ECSHOP---08---商品页的拇改成星星

<strong>用户评价&#xff1a;</strong>{*---------商品评价星星开始----------*}<img src"./images/stars{$goods.comment_rank}.gif" alt"comment rank {$goods.comment_rank}">{*---------商品评价星星结束-------*} 这里主要是要有星…

文件指针

一.移动文件指针 SetFilePointer,hFile,lDistanceToMove,lpDistanceToMoveHigh,dwMoveMethod dwMoveMethod 指明移动的模式 FILE_BEGIN 不管文件处于什么地方,总是从文件的头部开始移动,这时的位置参数相当于指定了一个绝对位置 FILE_CURRENT 从当前的文件指针处开始移…

见证下的自我变化-2014全年总结

又是一年总结季&#xff0c;回过头看看看自己的成长&#xff0c;心里真的是满满的喜悦之情…… 一年前自己的总结博客&#xff1a;http://blog.csdn.net/huo065000/article/details/19632603 半年前自己的总结博客&#xff1a;http://blog.csdn.net/huo065000/article/details/…

【Linux学习篇】This virtual machine is configured for 64-bit guest operating systems.……

在学习Linux的基本操作的时候&#xff0c;安装虚拟环境则提示自己 This virtualmachine is configured for 64-bit guest operatingsystems.……起初由于各种拒绝的心理&#xff0c;所以屏蔽了这个错误&#xff0c;但是屏蔽永远也解决不了问题的&#xff0c;所以自己则尝试百度…

图解SSIS监视文件夹并自动导入数据

图解SSIS监视文件夹并自动导入数据 原文:图解SSIS监视文件夹并自动导入数据 演示案例&#xff1a;让系统自动监视文件夹&#xff0c;并把文件夹下面的excel文件导入到sql中&#xff0c;之后清空目录。这个过程以往都需要写程序来实现或者定时执行&#xff0c;现在可以用ssis来订…

DLL转Lib

在C中,为了允许操作符重载和函数重载,C编译器往往按照某种规则改写每一个入口点的符号名,以便使用同一个名字(具有不同的参数类型或者是不同的作用域)有多种不同的用法,而不会打破现有基于C的链接器,.这项技术通常被称为改编(Name Mangling)或者名称修饰(Name Decoration),许多…

WP8手机解锁时提示“请确保IPOVERUSBSVC服务正常运行”解决方法

如果你各种重启服务 卸载手机 重装驱动都试过了还不行&#xff0c;请看看你是否安装了Hyper-v或Vitualbox虚拟机&#xff0c;很有可能是虚拟交换机造成的。 我在网络连接属性里看到这个 把它卸载后&#xff0c;解锁成功。 解锁后记得重新安装卸载的那个网络服务转载于:https://…

Win32路径操作相关API

一.路径截断与合并 PathRemoveArgs 去除路径的参数 PathRemoveBackslash 去除路径最后的反斜杠 "\" PathAddBackslash 在路径最后加上反斜杠 "\" PathRemoveBlanks 去除路径前后的空格 PathAddExtension 在文件路径后面加上扩展名 PathRemoveExtension 去…

Openjudge-计算概论(A)-称体重

描述&#xff1a; 赵、钱、孙、李四个人中既有大人也有小孩&#xff0c;给他们称体重时发现&#xff0c;他们每个人的体重都不一样&#xff0c;且体重&#xff08;单位&#xff1a;公斤&#xff09;恰好是10的整数倍&#xff0c;且他们的体重都不高 于50公斤&#xff0c;已知赵…

浮点数的存储

-------------------------------------------------------------------------------- 在VC6.0----float环境一共32位 其中第一位是符号位 第二到第9位中间8位为小数点位置&#xff08;指数以127的二进制为原点向下为负指数 向上为正指数&#xff09;后面23位为数据位。 S EE…