SEH 结构简介
好久都没有碰过 asm 了,今天工作需要,必须弄明白 seh 的问题。
所以,重新研究了一次,顺便记录一下,以被后用。
seh (Struct Exception Handling),详细情况清查询 msdn.
这里仅以我的一个小程序为例,展示 seh 的运作。
seh 的大致结构如下:
typedef
{
    DWORD dwNextSEHAddr;    // 下一个 SEH 结构地址
    DWORD dwHandlerAddr;    // 异常处理函数入口
}SEH;
从以上结构可以看出,一个 SEH 并不是孤立的,而是一个链表结构。
一个异常最终会传递给系统。这个链表的首部位于 fs:[0] 这个位置。
好了,我们通过一个小程序来说明这个(注:程序中是用了 stack 来存储 SEH,你也完全可以是用自己的内存空间)。
程序运行后,SEH 情况如图:
      stack
 +—————+
 | dwHandlerAddr | HiMem  
 |—————|   |
 | dwNextSEHAddr | LoMem  <——+
 +—————+               |
                                 |
                                 |
 +—————+               |
 |  SEH Pointer  | fs:[0] = esp -+
 +—————+
1. 首先通过 call 指令会自动压栈 dwHandlerAddr,
2. 然后利用 push dword ptr fs:[0] 指令,将原先的 SEH 地址存入 dwNextSEHAddr,构造 SEH 链表。
3. 这样我们就在栈中构造了我们的 SEH,最后把它插入到 SEH 链表的首部告知 windows 系统即可,这一步是用指令 mov fs:[0], esp 完成。
全部程序代码如下(注:以下代码是用 masm32 v8 编译通过):
=====================
.386
.model flat, stdcall
option casemap: none
include d:\masm32\include\windows.inc
include d:\masm32\include\kernel32.inc
include d:\masm32\include\user32.inc
includelib d:\masm32\lib\kernel32.lib
includelib d:\masm32\lib\user32.lib
.data
    szEx        db ‘Exception handled!’,0
    szOK        db ‘No Exception occurred!’,0
    szInfo        db ‘Info’,0
.code
start:
    xor edx, edx
    call handler    ; push handler_function_addr = $+3
    test eax, eax    ; exception occurred:  0 - yes, 1 - no
    jnz next
    mov esp, [esp+8]    ; restore stack after exception
    add esp, 8
    invoke MessageBox, 0, addr szEx, addr szInfo, 0
next:
    invoke ExitProcess, 0
handler:
    assume fs:nothing
    push dword ptr fs:[edx]
    mov fs:[edx], esp
    xor eax, eax
    ; if you don’t intent to occur excption,
    ; comment the next line code
    div eax
    pop dword ptr fs:[edx]    ; restore old SEH
    invoke MessageBox, 0, addr szOK, addr szInfo, 0
    mov eax, 1    ; no exception occurred
    ret
end    start
=====================
The End