标签:seh
前一篇文章vc++6对windows SEH扩展分析 尚有遗漏,本篇加以补齐。
其实本文参考csdn上一篇名为<Win32结构化异常处理(SEH)--异常处理程序(__try/except)>,同时提出了一些质疑。
作者罗列了vc++6.0扩展的SEH节点的结构如下:
struct _EXCEPTION_REGISTRATION { struct _EXCEPTION_REGISTRATION *prev; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD); struct scopetable_entry *scopetable; int trylevel; int _ebp; PEXCEPTION_POINTERS xpointers; };
如前一篇<vc++6对windows SEH扩展分析 >所述,这个结构是在进入函数时按push ebp/push 0xff一系列操作在堆栈上形成一个_EXCEPTION_REGISTRATION节点。一般而言push ebp是进入函数的第一条语句,那么,在栈中地址高于int _ebp的指针变量xpointers是谁压入的?一般而言,堆栈中[ebp+4]是函数返回地址,因此可以认为作者可能笔误写错了PEXCEPTION_POINTERS xpointers;在整个结构中的位置。那么,这个域在哪?本文通过调试代码,回答这个问题。
产生异常的代码如下:
#include <windows.h> int filter1(EXCEPTION_POINTERS* excpInfo) { DWORD accAddr = excpInfo->ExceptionRecord->ExceptionInformation[1]; excpInfo->ContextRecord; return EXCEPTION_EXECUTE_HANDLER; } int main() { int* a = NULL; __try { (*a)=0xcc; } __except(filter1(GetExceptionInformation())) { MessageBox(NULL,"","",MB_OK); } return 0; }程序触发异常后传入4个参数然后进入except_handler3,原型如下:
int __except_handler3( struct _EXCEPTION_RECORD * pExceptionRecord, struct EXCEPTION_REGISTRATION * pRegistrationFrame, struct _CONTEXT *pContextRecord, void * pDispatcherContext );
except_handler3源码没有,忍忍看看反汇编的结果:
__except_handler3: 00401234 push ebp 00401235 mov ebp,esp 00401237 sub esp,8 0040123A push ebx 0040123B push esi 0040123C push edi 0040123D push ebp 0040123E cld 0040123F mov ebx,dword ptr [ebp+0Ch] ;ebx指向第二个参数 00401242 mov eax,dword ptr [ebp+8] ;[ebp+8]指向第一个参数 00401245 test dword ptr [eax+4],6 0040124C jne __except_handler3+0A0h (004012d4) 00401252 mov dword ptr [ebp-8],eax 00401255 mov eax,dword ptr [ebp+10h] ;[ebp+10h]指向第三个参数 00401258 mov dword ptr [ebp-4],eax 0040125B lea eax,[ebp-8] 0040125E mov dword ptr [ebx-4],eax注释说了,ebx指向第二个参数,这个其实是发生异常前main函数中堆栈中压入的struct _EXCEPTION_REGISTRATION结构。这段代码中有这么几句:
00401242 mov eax,dword ptr [ebp+8] ;[ebp+8]指向第一个参数 <pre name="code" class="cpp">00401252 mov dword ptr [ebp-8],eax
... 00401255 mov eax,dword ptr [ebp+10h] ;[ebp+10h]指向第三个参数 00401258 mov dword ptr [ebp-4],eax ... <pre name="code" class="cpp">0040125E mov dword ptr [ebx-4],eax ;把结构的起始地址放入地址[pRegistrationFrame-4]
这段代码,把参数1 3放入某个结构中,然后把这个结构的地址传给[pRegistrationFrame-4],按照<Win32结构化异常处理(SEH)--异常处理程序(__try/except)>一文的作者描述,这个结构就是PEXCEPTION_POINTERS
xpointer。前面多次说过pRegistrationFrame是ide在堆栈上形成的结构,pRegistrationFrame-4相当于往堆栈上又压入一个4字节变量,因此,可以确定vc++6.0扩展的结构的原型应该是:
<pre name="code" class="cpp"><pre name="code" class="cpp">PEXCEPTION_POINTERS xpointers;struct _EXCEPTION_REGISTRATION {
触发异常之前,ebp=0x12ff48,trylevel=0x00,handler=0x403118,prev=0x12ff78;而0x12ff34,即xpointer处为0x83;
<pre name="code" class="cpp"><pre name="code" class="cpp">mov dword ptr [ebx-4],eax ;把结构的起始地址放入地址[pRegistrationFrame-4]
语句之后
0x12FF34处值为0x12FAEC。而地址0012FAEC处的内存为:
0012FAE4 00 00 00 00 00 00 00 00 ........ 0012FAEC E0 FB 12 00 FC FB 12 00 帑.... 0012FAF4 18 FB 12 00 79 71 85 77 ....yq厀明眼人一看0x12FBE0和0x12FBFC就知道是堆栈值。可以在按ebp的值查看函数参数和返回地址:
0012FAEC 25 E1 82 77 DD AE 6C 00 %醾w莓l. 0012FAF4 18 FB 12 00 79 71 85 77 ....yq厀 0012FAFC E0 FB 12 00 38 FF 12 00 帑..8... 0012FB04 FC FB 12 00 B4 FB 12 00这两个值果然是except_handler3的两个参数。
由此至少可以说明
<pre name="code" class="cpp"><pre name="code" class="cpp"><pre name="code" class="cpp">PEXCEPTION_POINTERS xpointers;struct _EXCEPTION_REGISTRATION {
00401273 push ebp 00401274 lea ebp,[ebx+10h] 00401277 call dword ptr [edi+ecx*4+4]call指令将调用scopetable数组中定义的过滤函数,然而在此之前except_handler3从[ebx+10h]处恢复ebp的值,那么[ebx+10h]是啥?首先可以确定ebx还是进入except_handler3时设置的ebx,其指向_EXCEPTION_REGISTRATION。_EXCEPTION_REGISTRATION+10H不就是_EXCEPTION_REGISTRATION!ebp吗?这个ebp是进入main函数时保存的函数帧,因此可以通过相对于ebp的偏移取得main函数中的变量。
至于GetExceptionInformation()函数,就是取except_handler3设置的xpointer地址:
18: __except(filter1(GetExceptionInformation())) 004010B5 mov ecx,dword ptr [ebp-14h] 004010B8 push ecx 004010B9 call @ILT+5(filter1) (0040100a) 004010BE add esp,4在正式进入过滤函数后,由于有一次push ebp修改了函数栈帧,因此不能在过滤函数用调用GetExceptionInformation
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:seh
原文地址:http://blog.csdn.net/lixiangminghate/article/details/47446589