http://www.kanxue.com/bbshtml/BBS4/kanxue310.htm SEH in ASM 研究
一个例子:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming >
; by 罗云彬, http://asm.yeah.net
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Unwind.asm
; 演示 SEH 链的回卷操作
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Unwind.asm
; Link /subsystem:windows Unwind.obj
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
szMsg1 db '这是外层异常处理程序(将处理异常)',0dh,0ah
db '异常发生位置:%08X,异常代码:%08X,标志:%08X',0
szMsg2 db '这是内层异常处理程序(对异常不进行处理)',0dh,0ah
db '异常发生位置:%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
szone1 db 'start',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 外层错误 Handler,将处理异常
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler1 proc _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext;_lpExceptionRecord指向一个Exception_Record结构
;_lpContext指向一个CONTEXT的结构,_lpSEH指向注册回调函数时使用的EXCEPTION_REGISTRATION结构的地址,_lpContext记录了异常产生时刻的运行环境
local @szBuffer[256]:byte
pushad ;利于模块化
mov esi,_lpExceptionRecord
mov edi,_lpContext
assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT,fs:nothing;启用fs寄存器
invoke wsprintf,addr @szBuffer,addr szMsg1,/
[edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlags;这是外层异常处理程序
invoke MessageBox,NULL,addr @szBuffer,NULL,MB_OK
;********************************************************************
; 将 EIP 指向安全的位置并恢复堆栈
;********************************************************************
mov eax,_lpSEH;EXCEPTION_REGISTRATION结构的地址
push [eax + 8h]
pop [edi].regEip
push _lpSEH
pop [edi].regEsp
;********************************************************************
; 对前面的 Handler 进行 Unwind 操作
;********************************************************************
invoke wsprintf,addr @szBuffer,addr szBeforeUnwind,dword ptr fs:[0];现在将开始 Unwind
invoke MessageBox,NULL,addr @szBuffer,addr szCaption,MB_OK
invoke RtlUnwind,_lpSEH,NULL,NULL,NULL;对当前回调函数之后的所有其他回调函数进行展开操作,FS[0]的地址发生了改变到handler2了
invoke wsprintf,addr @szBuffer,addr szAfterUnwind,dword ptr fs:[0];Unwind 返回
invoke MessageBox,NULL,addr @szBuffer,addr szCaption,MB_OK;FS[0]的地址又变回来了
;********************************************************************
assume esi:nothing,edi:nothing
popad
mov eax,ExceptionContinueExecution;如果可以正确处理的话,则写修正错误并将返回值设置为ExceptionContinueExecution
;如果返回ExceptionContinuesearch则重复查找
ret
_Handler1 endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 内层错误 Handler,不处理异常
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler2 proc _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext
local @szBuffer[256]:byte
pushad
mov esi,_lpExceptionRecord
mov edi,_lpContext
assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
invoke wsprintf,addr @szBuffer,addr szMsg2,/
[edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlags;这是内层异常处理程序
invoke MessageBox,NULL,addr @szBuffer,NULL,MB_OK
mov eax,_lpSEH;EXCEPTION_REGISTRATION结构的地址
push [eax + 8h];EXCEPTION_REGISTRATION结构have two words,one is prev ,the other is handler,the others is our data
pop [edi].regEip
push _lpSEH
pop [edi].regEsp;continue to point EXCEPTION_REGISTRATION
assume esi:nothing,edi:nothing
popad
mov eax,ExceptionContinueSearch;如果返回ExceptionContinuesearch则重复查找
ret
_Handler2 endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Test2 proc
assume fs:nothing
push offset _SafePlace
;invoke RtlUnwind,_lpSEH,NULL,NULL,NULL;对当前回调函数之后的所有其他回调函数进行展开操作
;_SafePlace;不是回调函数所以就。。。。。。。。。。。不知道是不是这个原因,那为什么又执行后面的_SafePlace呢
;这句去掉也没什么影响,为什么
push offset _Handler2
push fs:[0]
mov fs:[0],esp;第一条push offset _Handler指令将回调函数的地址推入堆栈;第二条push fs:[0]指令则将当前使用的EXCEPTION_ REGISTRATION结构地址推入堆栈,
;现在堆栈指针esp指向的地方刚好是一个新的EXCEPTION_REGISTRATION结构——[esp]等于原结构地址,也就是prev字段,而[esp+4]等于回调函数地址,也就是handler字段;
;当第三条指令mov fs:[0],esp将esp的值放入fs:[0]后,设置工作就完成了!需要注意的是,原先的结构地址必须被保存到prev字段中。
;********************************************************************
; 会引发异常的指令
;********************************************************************
pushad
invoke MessageBox,NULL,addr szone1,addr szCaption,MB_OK
xor eax,eax
mov dword ptr [eax],0
popad ;这一句将无法被执行
_SafePlace: ;这个函数也可以去掉为什么不能执行呢
invoke MessageBox,NULL,addr szSafe2,addr szCaption,MB_OK;回到了内层子程序的安全位置,竟然没用。。。有问题,没有设置EIP,设置后就正常运行这个消息框
pop fs:[0]
add esp,8
ret
_Test2 endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Test1 proc
assume fs:nothing
push offset _SafePlace
push offset _Handler1
push fs:[0]
mov fs:[0],esp
invoke _Test2
_SafePlace:
invoke MessageBox,NULL,addr szSafe1,addr szCaption,MB_OK;回到了外层子程序的安全位置
pop fs:[0]
add esp,8
ret
_Test1 endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
invoke _Test1
invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start