这是一段简单的SEH测试,麻雀虽小,但五脏俱全
从这个代码中就可以看到一个SEH处理的大致流程了:
引发异常->查找EXCEPTION_REGISTRATION找出异常处理函数->处理异常->控制代码流
_asm
{
push handler
push fs:[0]
mov FS:[0],ESP
}
这么一段代码很多书上介绍是保存老的EXCEPTION_REGISTRATION结构体的入口地址
用2005跟踪了下汇编代码后发现,其实这样的说法很含糊,容易混淆人,当初没跟踪前我就很混淆
跟踪代码和察看内存数据后发现,其实这是一个链表插入的过程,为了方便叙述EXCEPTION_REGISTRATION 结构体 简称(ER),流程如下:
ER是一个线性的单向链表 链表中每个节点都是相同的ER结构 FS:[0]永远指向这个链表的第一个节点,也就是链表头
在这个程序开始前,FS:[0]指向的是表头ER1,这个表头的ER结构里的handler肯定不是指向我们自己定义的异常处理函数
所以我们要建立一个能够指向自己的异常处理函数的ER结构ER2
push handler push fs:[0] 这2句就实现了我们的目的,这2句执行后得出的ESP
然后传递给FS:[0] ,这样表头就不在是原来的ER1而是ER2了
ER的链表结构由原先的:ER1->ER->-ER->ER
而变成了现在的: ER2->ER1->ER->ER->ER
短短3句代码其实的操作就是ER链表的插入过程
而下面的代码:
_asm
{
mov eax, [ESP]
mov fs:[0], eax
add esp,8
}
则很好理解了,是断开我们的字定义ER2结构,恢复原始链表样子,并释放堆栈
以上是在VS2005下跟踪调试得出的结论,如果有问题,就指出来
写出来也是帮助下可能有疑惑的人或者还没真正弄明白的人把.
BTW: 其实我想不一定非要用堆栈来实现以上的SEH代码,因为ER结构的第一个成员是PREV,第2个成员是HANDLER, 只要能保证ER结构是在线性的内存上存储,就可以
书里一般用堆栈我想是为了直观的目的把