Windows 下的异常可以有两种方式:筛选器异常处理和SEH异常处理
筛选器异常处理的方式是由程序指定一个异常处理回调函数,当发生异常的时候,系统将调用这个回调函数,并根据这个回调函数的返回值决定如何进行下一步操作,这种方式和DOS系统中使用INT24h中断处理异常的方法和像的
在进程范围内,筛选器的回调函数是唯一的,设置一个新的回调函数后,原来的回调函数就失效了。
注册回调函数
可以使用 SetUnHandledExceptionFilter 函数来设置一个筛选器异常处理的回调函数,准确的讲,这个回调函数不是替换了系统默认的异常处理程序,而是在它前面进行了一些预处理,操作的结果还是会被送到系统默认的异常处理程序中去,这个过程就相当于对异常进行了一次“筛选”
SetUnHandledExceptionFilter 函数的使用方法:
invoke SetUnHandledExceptionFilter,offset Handler
mov lpOldHandler,eax
函数的唯一参数是回调函数的地址,如果地址是NULL,那么系统将去掉这个“筛子”而直接将异常送往系统默认的异常处理程序。函数返回值是上一次设置的回调函数的入口地址,如果原来没有安装“筛子”,那么返回NULL
如果原来已经设置了一个回调函数的话,那么新的回调函数将会替换掉原来的回调函数,注意:不是在原先得回调函数前面再挂上新的回调函数。也就是说,当发生异常时,系统调用新的回调函数,在这个函数返回的时候并不会在调用上一次设置的回调函数。
例子
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;include 定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
lpOldHandler dd ? ;记录上一次设置的回调函数的地址
.const
szMsg db '异常发生位置:%08x,异常代码:%08x,标志:%08x',0
szSafe db '回到了安全的地方',0
szCaption db '筛选器异常处理的例子',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;Exception Handler 异常处理程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler proc _lpExceptionPoint
LOCAL @szBuffer[256]:byte ;声明一个局部缓冲区
pushad ;保护现场
mov esi,_lpExceptionPoint
assume esi:ptr EXCEPTION_POINTERS ;声明esi为EXCEPTION_POINTERS结构体类型
mov edi,[esi].ContextRecord
mov esi,[esi].pExceptionRecord
assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
invoke wsprintf,addr @szBuffer,offset szMsg,[edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlags
invoke MessageBox,NULL,addr @szBuffer,offset szCaption,MB_OK
mov [edi].regEip,offset _SafePlace ;回调函数结束后要返回到改地址处继续执行
assume esi:nothing,edi:nothing
popad
mov eax,EXCEPTION_CONTINUE_EXECUTION
ret
_Handler endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
invoke SetUnhandledExceptionFilter,offset _Handler ;设置筛选回调函数
mov lpOldHandler,eax
mov eax,11
mov bx,0
div bx ;引发异常处理的代码
_SafePlace:
invoke MessageBox,NULL,offset szSafe,offset szCaption,MB_OK
invoke SetUnhandledExceptionFilter,lpOldHandler
invoke ExitProcess,NULL ;结束进程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
筛选器异常处理回调函数的格式:
_Handler proc lpExceptionInfo
回调函数的参数是指向EXCEPTION_POINTERS结构体的指针
由于字数限制将会在下一章写完余下的内容