在学习《Win32 结构化异常处理(SEH)揭秘》的过程中,里面有一段示例代码(ShowSEHFrames.cpp)在试验中没有得到预期的结果,追踪过程中发现,VS2005内置的C/C++编译器的异常处理函数是_except_handler4而非_except_handler3,而且ScopeTable也被简单加密处理过,就是这样才导致示例程序pScopeTableEntry的所有指向均出错(如:pScopeTableEntry->lpfnHandler)。本文通过调试跟踪,希望能够理解一点Win32结构化异常处理的真实过程。
1)用于调试的源代码(在《Win32 结构化异常处理(SEH)揭秘》中)
2)对Function1下断点,运行、中断。转到反汇编。得到Function1的汇编代码
这里要注意的是在0x004115B6处,ScopeTable被加密处理了。因此ShowSEHFrame函数在采用类似下面的代码时没办法输出scopetable数组的所有信息。
F11跟进0x004115DD,我们来到WalkSEHFrames!
WalkSEHFrames代码较好理解,就不做分析了。我们继续F11跟进0x00411534,来到ShowSEHFrame。
代码运行到0x00411435,暂停一下。分析在0x00411438处,由于从还没有解密的scopetable中去获取__try/__except过滤函数将导致非法内存访问,最终它被安装在系统上的异常处理程序所处理。其实也就是pVCExcRec->handler,观察一下pVCExcRec->handler的值,发现它指向_except_handler4。对_except_handler4下断,程序继续单步运行,来到_except_handler4。
观察局部变量
F11单步进入__except_handler4_common。
... ...
根据以上分析,要输出正确结果就必须解密ScopeTable(安全码由系统生成,VS2005调试版本下固定放在[00417000h],Release版本下固定存放在[0040C000h]处),解密后的ScopeTable+0x10才是真正的ScopeTable位置。
更改后,代码如下,运行正确。
第三个帧来自 Visual C++ 运行时库。Visual C++ 运行时库源代码中的 CRT0.C 文件清楚地表明了对 main 或 WinMain 的调用也被一个__try/__except 块封装着(跟踪发现其异常处理程序仍然是_except_handler4)。
最后一个帧的异常处理程序的地址是7C839AF0,这与其它三个不同。这个地址在 KERNEL32.DLL,是一个名叫_except_handler3的异常处理程序。:-)
附:更改前的运行状况