zoukankan      html  css  js  c++  java
  • SEH简单研究

    开发过程中总会遇到不可预测的异常奔溃,对于异常机制也是一直没有弄得个清清楚楚明明白白.今天准备重温一下WINDOWS SEH机制加深印象.对于WINDOWS SEH原理研究的比较透彻的莫过于Matt Pietrek的A Crash Course on the Depths of Win32™ Structured Exception Handling,在该文中详细的讲述的WINDOWS异常处理的机制构成原理.

    个人的思路基本上是先模拟异常,然后利用windbg调试相应的异常来验证Matt Pietrek所说的异常处理.

    //异常处理中再次抛出异常
    void OnExceptionOccuered(exception *ex) { __try { const char* pszException = ex->what(); delete ex; throw pszException; } __except(Eval_Exception(GetExceptionCode())) { } }
    //在能整除2时抛出异常 VOID CPPExceptionTest() { try { _except_handler4 int r=rand(); cout<<"value "<<r; if((r%2)==0) throw new exception("Cpp Exception"); } catch (exception* e) { cout<<"exception info\t"<<e->what()<<"occur\n"; //delete e; OnExceptionOccuered(e); } } //异常过滤处理函数 int Eval_Exception( int iExceptionCode) { if ( iExceptionCode != STATUS_INTEGER_OVERFLOW && iExceptionCode != STATUS_FLOAT_OVERFLOW ) // Pass on most exceptions return EXCEPTION_CONTINUE_SEARCH; // Execute some code to clean up problem ResetVars( 0 ); // initializes data to 0 return EXCEPTION_CONTINUE_EXECUTION; _EXCEPITON_REGISTARTION_RECORD }

    //模拟不同线程间互相操作抛出异常情景 DWORD WINAPI ThreadProc( __in LPVOID lpParameter ) { HANDLE hEvent = (HANDLE)lpParameter; while(true) { CPPExceptionTest(); } SetEvent(hEvent); return 1; } //主函数 int _tmain(int argc, _TCHAR* argv[]) { HANDLE hThreadEvents[10]={NULL}; for(int i=0; i < 10;i++) { hThreadEvents[i] = CreateEvent(NULL,TRUE,FALSE,NULL); CreateThread(NULL,0,&ThreadProc,hThreadEvents[i],0,NULL); } while(WaitForMultipleObjects(10,hThreadEvents,TRUE,INFINITE) != WAIT_OBJECT_0) { continue; } return 0; }

    Release编译之后通过windbg加载调试,在运行过程中会发现不断的出现

    (1c08.444): C++ EH exception - code e06d7363 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    eax=005dfab4 ebx=00000000 ecx=00000003 edx=00000000 esi=00495e50 edi=00000000
    eip=75219617 esp=005dfab4 ebp=005dfb04 iopl=0         nv up ei pl nz ac pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
    KERNELBASE!RaiseException+0x58:
    75219617 c9              leave
    

    当然这时候如果查看调用堆栈可以很清楚的看到相应的出错位置,通过windbg的k命令可以很清楚的看到调用堆栈如下

    0:001> kv
    ChildEBP RetAddr  Args to Child              
    005dfb04 6fac7819 e06d7363 00000001 00000003 KERNELBASE!RaiseException+0x58 (FPO: [Non-Fpo])
    005dfb3c 00131170 005dfb64 001323f8 65e7a5bf MSVCR100!_CxxThrowException+0x48 (FPO: [Non-Fpo]) (CONV: stdcall) [f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 157]
    005dfb7c 00131205 75cc1174 00000020 005dfbcc Win32ExRes!CPPExceptionTest+0xb0 (FPO: [Non-Fpo]) (CONV: cdecl) [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 50]
    005dfb80 75cc1174 00000020 005dfbcc 771eb3f5 Win32ExRes!ThreadProc+0x5 (FPO: [1,0,0]) (CONV: stdcall) [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 75]
    005dfb8c 771eb3f5 00000020 65c6ac80 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
    005dfbcc 771eb3c8 00131200 00000020 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
    005dfbe4 00000000 00131200 00000020 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
    

    对于异常值得关注的肯定是自己编写的代码,这里的CPPExceptionTest函数的处理值得深度怀疑,可以看一下该函数相关内容基本上可以定位到相应的抛出异常的位置.并加以修复

    为了加深对于异常处理的理解,我们对于这种情形不予处理,如果这中异常抛出之后没有人处理则根据Matt Pietrek的理论系统会掉用UnhandledExceptionFilter进行默认处理.那么我们可以在UnhandledExceptionFilter这里下一个断点.对于RaiseException则不予理睬,将会发现系统将在UnhandledExceptionFilter处中断.使用kv命令查看调用堆栈.

    0:008> kv
    ChildEBP RetAddr  Args to Child              
    0113f204 77205a74 0113f234 771ad950 00000000 kernel32!UnhandledExceptionFilter (FPO: [Non-Fpo])
    0113f20c 771ad950 00000000 0113fdcc 771e0598 ntdll!__RtlUserThreadStart+0x62 (FPO: [SEH])
    0113f220 771ad7ec 00000000 00000000 00000000 ntdll!_EH4_CallFilterFunc+0x12 (FPO: [Uses EBP] [0,0,4])
    0113f248 771d65f9 fffffffe 0113fdbc 0113f354 ntdll!_except_handler4+0x8e (FPO: [Non-Fpo])
    0113f26c 771d65cb 0113f334 0113fdbc 0113f354 ntdll!ExecuteHandler2+0x26
    0113f31c 771d6457 0013f334 0113f354 0113f334 ntdll!ExecuteHandler+0x24
    0113f31c 75219617 0013f334 0113f354 0113f334 ntdll!KiUserExceptionDispatcher+0xf (FPO: [2,0,0]) (CONTEXT @ 0113f354)
    0113f688 6fac7819 e06d7363 00000001 00000003 KERNELBASE!RaiseException+0x58 (FPO: [Non-Fpo])
    0113f6c0 0013105f 0113f6e4 001323c0 64a9a9cb MSVCR100!_CxxThrowException+0x48 (FPO: [Non-Fpo]) (CONV: stdcall) [f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 157]
    0113f708 001311ae 6faa2de7 0113fd70 0113f9b0 Win32ExRes!OnExceptionOccuered+0x5f (FPO: [Non-Fpo]) (CONV: cdecl) [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 21]
    0113fd7c 00131205 75cc1174 00000060 0113fdcc Win32ExRes!CPPExceptionTest+0xee (FPO: [Non-Fpo]) (CONV: cdecl) [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 53]
    0113fd80 75cc1174 00000060 0113fdcc 771eb3f5 Win32ExRes!ThreadProc+0x5 (FPO: [1,0,0]) (CONV: stdcall) [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 75]
    0113fd8c 771eb3f5 00000060 6488aa80 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
    0113fdcc 771eb3c8 00131200 00000060 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
    0113fde4 00000000 00131200 00000060 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
    

    可以看到 

    0113f204 77205a74 0113f234 771ad950 00000000 kernel32!UnhandledExceptionFilter (FPO: [Non-Fpo])

    而UnhandledExceptionFilter的函数原型如下

    	__callback
    	WINBASEAPI
    	LONG
    	WINAPI
    	UnhandledExceptionFilter(
    	    __in struct _EXCEPTION_POINTERS *ExceptionInfo
    	    );
    	
    	typedef struct _EXCEPTION_POINTERS {
    	    PEXCEPTION_RECORD ExceptionRecord; //异常信息
    	    PCONTEXT ContextRecord;//异常上下文
    	} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
    

    利用dd命令查看相关参数

    0:008> dd 0113f234 
    0113f234  0113f334 0113f354 771e05a8 00000001
    0113f244  00854744 0113f26c 771d65f9 fffffffe
    0113f254  0113fdbc 0113f354 0113f308 0113f6f8
    0113f264  771d660d 0113fdbc 0113f31c 771d65cb
    0113f274  0113f334 0113fdbc 0113f354 0113f308
    0113f284  771ad74d 00000000 0113f334 0113fdbc
    0113f294  771b8d3d 0113f334 0113fdbc 0113f354
    0113f2a4  0113f308 771ad74d 00495f18 0113f334
    0:008> .exr 0113f334 
    ExceptionAddress: 75219617 (KERNELBASE!RaiseException+0x00000058)
       ExceptionCode: e06d7363 (C++ EH exception)
      ExceptionFlags: 00000001
    NumberParameters: 3
       Parameter[0]: 19930520
       Parameter[1]: 0113f6e4
       Parameter[2]: 001323c0
      pExceptionObject: 0113f6e4
      _s_ThrowInfo    : 001323c0
      Type            : char *
      Type            : void *
    0:008> .cxr 0113f354 
    eax=0113f638 ebx=00131170 ecx=00000003 edx=00000000 esi=00495ef0 edi=00495f18
    eip=75219617 esp=0113f638 ebp=0113f688 iopl=0         nv up ei pl nz ac po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
    KERNELBASE!RaiseException+0x58:
    75219617 c9              leave
    0:008> k
      *** Stack trace for last set context - .thread/.cxr resets it
    ChildEBP RetAddr  
    0113f688 6fac7819 KERNELBASE!RaiseException+0x58
    0113f6c0 0013105f MSVCR100!_CxxThrowException+0x48 [f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 157]
    0113f708 001311ae Win32ExRes!OnExceptionOccuered+0x5f [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 21]
    0113fd7c 00131205 Win32ExRes!CPPExceptionTest+0xee [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 53]
    0113fd80 75cc1174 Win32ExRes!ThreadProc+0x5 [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 75]
    0113fd8c 771eb3f5 kernel32!BaseThreadInitThunk+0xe
    0113fdcc 771eb3c8 ntdll!__RtlUserThreadStart+0x70
    0113fde4 00000000 ntdll!_RtlUserThreadStart+0x1b
    

    如此基本已经还原系统抛出异常时的调用堆栈

    dd来查看异常上下文信息

    0:008> dd 0113f354 
    0113f354  0001003f 00000000 00000000 00000000
    

    可以发现异常上下文对应前四个字节内容为0x0001003f所以我们可以在内存中通过该关键字来查找相应的异常信息

    0:008> s -d 0113d000 L1000 1003f
    0113f354  0001003f 00000000 00000000 00000000  ?...............
    0113f9d0  0001003f 00000000 00000000 00000000  ?...............
    0:008> .cxr 0113f354  
    eax=0113f638 ebx=00131170 ecx=00000003 edx=00000000 esi=00495ef0 edi=00495f18
    eip=75219617 esp=0113f638 ebp=0113f688 iopl=0         nv up ei pl nz ac po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
    KERNELBASE!RaiseException+0x58:
    75219617 c9              leave
    0:008> k
      *** Stack trace for last set context - .thread/.cxr resets it
    ChildEBP RetAddr  
    0113f688 6fac7819 KERNELBASE!RaiseException+0x58
    0113f6c0 0013105f MSVCR100!_CxxThrowException+0x48 [f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 157]
    0113f708 001311ae Win32ExRes!OnExceptionOccuered+0x5f [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 21]
    0113fd7c 00131205 Win32ExRes!CPPExceptionTest+0xee [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 53]
    0113fd80 75cc1174 Win32ExRes!ThreadProc+0x5 [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 75]
    0113fd8c 771eb3f5 kernel32!BaseThreadInitThunk+0xe
    0113fdcc 771eb3c8 ntdll!__RtlUserThreadStart+0x70
    0113fde4 00000000 ntdll!_RtlUserThreadStart+0x1b
    0:008> .cxr 0113f9d0  
    eax=0113fcb4 ebx=00000000 ecx=00000003 edx=00000000 esi=00495ef0 edi=00000000
    eip=75219617 esp=0113fcb4 ebp=0113fd04 iopl=0         nv up ei pl nz ac pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
    KERNELBASE!RaiseException+0x58:
    75219617 c9              leave
    0:008> k
      *** Stack trace for last set context - .thread/.cxr resets it
    ChildEBP RetAddr  
    0113fd04 6fac7819 KERNELBASE!RaiseException+0x58
    0113fd3c 00131170 MSVCR100!_CxxThrowException+0x48 [f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 157]
    0113fd7c 00131205 Win32ExRes!CPPExceptionTest+0xb0 [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 50]
    0113fd80 75cc1174 Win32ExRes!ThreadProc+0x5 [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 75]
    0113fd8c 771eb3f5 kernel32!BaseThreadInitThunk+0xe
    0113fdcc 771eb3c8 ntdll!__RtlUserThreadStart+0x70
    0113fde4 00000000 ntdll!_RtlUserThreadStart+0x1b
    

    如此也可以跟踪到相应的异常调用堆栈信息从而确定具体抛出异常的位置.

    到这里基本上已经可以通过windbg对异常进行相应的调试跟踪,进而籍此跟踪结果对这些异常进行修复.

    但是这样我们并不能跟踪Matt Pietrek提到的WINDOWS的异常处理机制,那么按照Matt Pietrek的说法我们来看看WINDOWS是如何利用SEH对异常进行处理呢?

    通过!teb获取对应的线程信息

    0:008> !teb
    TEB at 7ffd6000
        ExceptionList:        0113f260
        StackBase:            01140000
        StackLimit:           0113d000
        SubSystemTib:         00000000
        FiberData:            00001e00
        ArbitraryUserPointer: 00000000
        Self:                 7ffd6000
        EnvironmentPointer:   00000000
        ClientId:             00001c08 . 0000192c
        RpcHandle:            00000000
        Tls Storage:          7ffd602c
        PEB Address:          7ffd8000
        LastErrorValue:       87
        LastStatusValue:      c000000d
        Count Owned Locks:    0
        HardErrorMode:        0
    

    teb数据结构为 _TEB,使用dt命令查看详细信息

    0:008> dt 7ffd6000 _TEB
    Win32ExRes!_TEB
       +0x000 NtTib            : _NT_TIB
       +0x01c EnvironmentPointer : (null) 
       +0x020 ClientId         : _CLIENT_ID
       +0x028 ActiveRpcHandle  : (null) 
       +0x02c ThreadLocalStoragePointer : 0x7ffd602c Void
       +0x030 ProcessEnvironmentBlock : 0x7ffd8000 _PEB
       +0x034 LastErrorValue   : 0x57
       +0x038 CountOfOwnedCriticalSections : 0
       +0x03c CsrClientThread  : (null) 
       +0x040 Win32ThreadInfo  : (null) 
       +0x044 User32Reserved   : [26] 0
       +0x0ac UserReserved     : [5] 0
       +0x0c0 WOW32Reserved    : (null) 
       +0x0c4 CurrentLocale    : 0x804
       +0x0c8 FpSoftwareStatusRegister : 0
       +0x0cc SystemReserved1  : [54] (null) 
       +0x1a4 ExceptionCode    : 0n0
       +0x1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
       +0x1bc SpareBytes1      : [24]  ""
       +0x1d4 GdiTebBatch      : _GDI_TEB_BATCH
       +0x6b4 RealClientId     : _CLIENT_ID
       +0x6bc GdiCachedProcessHandle : (null) 
       +0x6c0 GdiClientPID     : 0
       +0x6c4 GdiClientTID     : 0
       +0x6c8 GdiThreadLocalInfo : (null) 
       +0x6cc Win32ClientInfo  : [62] 0
       +0x7c4 glDispatchTable  : [233] (null) 
       +0xb68 glReserved1      : [29] 0
       +0xbdc glReserved2      : (null) 
       +0xbe0 glSectionInfo    : (null) 
       +0xbe4 glSection        : (null) 
       +0xbe8 glTable          : (null) 
       +0xbec glCurrentRC      : (null) 
       +0xbf0 glContext        : (null) 
       +0xbf4 LastStatusValue  : 0xc000000d
       +0xbf8 StaticUnicodeString : _UNICODE_STRING ""
       +0xc00 StaticUnicodeBuffer : [261]  ""
       +0xe0c DeallocationStack : 0x01040000 Void
       +0xe10 TlsSlots         : [64] (null) 
       +0xf10 TlsLinks         : _LIST_ENTRY [ 0x0 - 0x0 ]
       +0xf18 Vdm              : (null) 
       +0xf1c ReservedForNtRpc : (null) 
       +0xf20 DbgSsReserved    : [2] (null) 
       +0xf28 HardErrorMode    : 0
       +0xf2c Instrumentation  : [16] (null) 
       +0xf6c WinSockData      : (null) 
       +0xf70 GdiBatchCount    : 0
       +0xf74 InDbgPrint       : 0 ''
       +0xf75 FreeStackOnTermination : 0 ''
       +0xf76 HasFiberData     : 0x1 ''
       +0xf77 IdealProcessor   : 0x1 ''
       +0xf78 Spare3           : 0
       +0xf7c ReservedForPerf  : (null) 
       +0xf80 ReservedForOle   : (null) 
       +0xf84 WaitingOnLoaderLock : 0
       +0xf88 Wx86Thread       : _Wx86ThreadState
       +0xf94 TlsExpansionSlots : (null) 
       +0xf98 ImpersonationLocale : 0
       +0xf9c IsImpersonating  : 0
       +0xfa0 NlsCache         : (null) 
       +0xfa4 pShimData        : (null) 
       +0xfa8 HeapVirtualAffinity : 0
       +0xfac CurrentTransactionHandle : (null) 
       +0xfb0 ActiveFrame      : (null) 
       +0xfb4 FlsData          : 0x00184c40 Void
    

    _NT_TIB中包含有异常注册信息

    0:008> dt 7ffd6000  _NT_TIB
    Win32ExRes!_NT_TIB
       +0x000 ExceptionList    : 0x0113f260 _EXCEPTION_REGISTRATION_RECORD
       +0x004 StackBase        : 0x01140000 Void
       +0x008 StackLimit       : 0x0113d000 Void
       +0x00c SubSystemTib     : (null) 
       +0x010 FiberData        : 0x00001e00 Void
       +0x010 Version          : 0x1e00
       +0x014 ArbitraryUserPointer : (null) 
       +0x018 Self             : 0x7ffd6000 _NT_TIB
    

    在利用dt查看_EXCEPTION_REGISTRATION_RECORD信息

    0:008> dt 0x0113f260  _EXCEPTION_REGISTRATION_RECORD -r
    Win32ExRes!_EXCEPTION_REGISTRATION_RECORD
       +0x000 Next             : 0x0113f6f8 _EXCEPTION_REGISTRATION_RECORD
          +0x000 Next             : 0x0113f740 _EXCEPTION_REGISTRATION_RECORD
             +0x000 Next             : 0x0113f7b0 _EXCEPTION_REGISTRATION_RECORD
             +0x004 Handler          : 0x6fb238aa           _EXCEPTION_DISPOSITION  MSVCR100!CatchGuardHandler+0
          +0x004 Handler          : 0x00131d59        _EXCEPTION_DISPOSITION  Win32ExRes!_except_handler4+0
       +0x004 Handler          : 0x771d660d     _EXCEPTION_DISPOSITION  ntdll!ExecuteHandler2+0
    

    到这里基本上可以看到该线程有3个异常处理函数

    0:008> ln 0x6fb238aa           
    f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\i386\trnsctrl.cpp(541)
    (6fb238aa)   MSVCR100!CatchGuardHandler   |  (6fb238dd)   MSVCR100!_CallSETranslator
    Exact matches:
        MSVCR100!CatchGuardHandler (void)
    0:008> ln 0x00131d59        
    (00131d59)   Win32ExRes!_except_handler4   |  (00131d7e)   Win32ExRes!_setdefaultprecision
    Exact matches:
        Win32ExRes!_except_handler4 (void)
    0:008> ln 0x771d660d     
    (771d65d3)   ntdll!ExecuteHandler2+0x3a   |  (771d665b)   ntdll!RtlpUnlinkHandler
    

    相应的在KiUserExceptionDispatcher函数对异常进行分发时会使用到这些异常处理函数。这个函数在NTDLL.DLL中,它是异常处理执行的起点 

    分别对该3个函数下断点

    0:001> bp ntdll!ExecuteHandler2
    0:001> bp Win32ExRes!_except_handler4
    0:001> bp MSVCR100!CatchGuardHandler

    马上就会在这些断点中中断下来

    ChildEBP RetAddr  
    006df8e8 771d65cb ntdll!ExecuteHandler2
    006df998 771d6457 ntdll!ExecuteHandler+0x24
    006df998 75219617 ntdll!KiUserExceptionDispatcher+0xf
    006dfd04 6fac7819 KERNELBASE!RaiseException+0x58
    006dfd3c 011a1170 MSVCR100!_CxxThrowException+0x48 [f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 157]
    006dfd7c 011a1205 Win32ExRes!CPPExceptionTest+0xb0 [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 50]
    006dfd80 75cc1174 Win32ExRes!ThreadProc+0x5 [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 75]
    006dfd8c 771eb3f5 kernel32!BaseThreadInitThunk+0xe
    006dfdcc 771eb3c8 ntdll!__RtlUserThreadStart+0x70
    006dfde4 00000000 ntdll!_RtlUserThreadStart+0x1b
    

    到这里可以断定KiUserExceptionDispatcher->ExecuteHandler->ExecuteHandler2

    有时也会调用到_except_handler4

    ChildEBP RetAddr  
    006df248 771d65f9 Win32ExRes!_except_handler4
    006df26c 771d65cb ntdll!ExecuteHandler2+0x26
    006df31c 771d6457 ntdll!ExecuteHandler+0x24
    006df31c 75219617 ntdll!KiUserExceptionDispatcher+0xf
    006df688 6fac7819 KERNELBASE!RaiseException+0x58
    006df6c0 011a105f MSVCR100!_CxxThrowException+0x48 [f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 157]
    006df708 011a11ae Win32ExRes!OnExceptionOccuered+0x5f [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 21]
    006dfd7c 011a1205 Win32ExRes!CPPExceptionTest+0xee [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 53]
    006dfd80 75cc1174 Win32ExRes!ThreadProc+0x5 [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 75]
    006dfd8c 771eb3f5 kernel32!BaseThreadInitThunk+0xe
    006dfdcc 771eb3c8 ntdll!__RtlUserThreadStart+0x70
    006dfde4 00000000 ntdll!_RtlUserThreadStart+0x1b
    

    跟踪ntdll!ExecuteHandler2的运行发现

    771d65da 64ff3500000000  push    dword ptr fs:[0]	//fs:003b:00000000=006df6f8
    
    0:001> dt 006df6f8 _EXCEPTION_REGISTRATION_RECORD -r
    Win32ExRes!_EXCEPTION_REGISTRATION_RECORD
       +0x000 Next             : 0x006df740 _EXCEPTION_REGISTRATION_RECORD
          +0x000 Next             : 0x006df7b0 _EXCEPTION_REGISTRATION_RECORD
             +0x000 Next             : 0x006df8dc _EXCEPTION_REGISTRATION_RECORD
             +0x004 Handler          : 0x6fb2b582           _EXCEPTION_DISPOSITION  MSVCR100!_except_handler4+0
          +0x004 Handler          : 0x6fb238aa        _EXCEPTION_DISPOSITION  MSVCR100!CatchGuardHandler+0
       +0x004 Handler          : 0x011a1d59     _EXCEPTION_DISPOSITION  Win32ExRes!_except_handler4+0
    

    跟踪可以发现相应会调用到CatchGuardHandler以及_except_handler4相应参考Matt Pietrek文章逻辑基本应该如下:  

    Win32ExRes!_except_handler4:
    011a1d59 8bff            mov     edi,edi
    011a1d5b 55              push    ebp
    011a1d5c 8bec            mov     ebp,esp
    011a1d5e ff7514          push    dword ptr [ebp+14h]
    011a1d61 ff7510          push    dword ptr [ebp+10h]
    011a1d64 ff750c          push    dword ptr [ebp+0Ch]
    011a1d67 ff7508          push    dword ptr [ebp+8]
    011a1d6a 686d151a01      push    offset Win32ExRes!__security_check_cookie (011a156d)
    011a1d6f 6818301a01      push    offset Win32ExRes!__security_cookie (011a3018)
    011a1d74 e8ef000000      call    Win32ExRes!except_handler4_common (011a1e68)
    011a1d79 83c418          add     esp,18h
    011a1d7c 5d              pop     ebp
    011a1d7d c3              ret 
    MSVCR100!_except_handler4_common:
    6fb2cb44 8bff            mov     edi,edi
    6fb2cb46 55              push    ebp
    6fb2cb47 8bec            mov     ebp,esp
    6fb2cb49 83ec18          sub     esp,18h
    6fb2cb4c 8b4508          mov     eax,dword ptr [ebp+8]
    6fb2cb4f 53              push    ebx
    6fb2cb50 8b5d14          mov     ebx,dword ptr [ebp+14h]
    6fb2cb53 56              push    esi
    6fb2cb54 8b7308          mov     esi,dword ptr [ebx+8]
    6fb2cb57 3330            xor     esi,dword ptr [eax]
    6fb2cb59 57              push    edi
    6fb2cb5a 8b06            mov     eax,dword ptr [esi]
    6fb2cb5c c645ff00        mov     byte ptr [ebp-1],0
    6fb2cb60 c745f401000000  mov     dword ptr [ebp-0Ch],1
    6fb2cb67 8d7b10          lea     edi,[ebx+10h]
    6fb2cb6a 83f8fe          cmp     eax,0FFFFFFFEh
    6fb2cb6d 740b            je      MSVCR100!_except_handler4_common+0x36 (6fb2cb7a)
    6fb2cb6f 8b4e04          mov     ecx,dword ptr [esi+4]
    6fb2cb72 03cf            add     ecx,edi
    6fb2cb74 330c38          xor     ecx,dword ptr [eax+edi]
    6fb2cb77 ff550c          call    dword ptr [ebp+0Ch] //ss:0023:00e5f114={Win32ExRes!__security_check_cookie (0136156d)}
    6fb2cb7a 8b4e0c mov ecx,dword ptr [esi+0Ch]
    6fb2cb7d 8b5608 mov edx,dword ptr [esi+8]
    6fb2cb80 03cf            add     ecx,edi
    6fb2cb82 330c3a          xor     ecx,dword ptr [edx+edi]
    6fb2cb85 ff550c          call    dword ptr [ebp+0Ch]  
    6fb2cb88 8b4510          mov     eax,dword ptr [ebp+10h]
    6fb2cb8b f6400466        test    byte ptr [eax+4],66h
    6fb2cb8f 0f850d010000    jne     MSVCR100!_except_handler4_common+0x166 (6fb2cca2)
    6fb2cb95 8d4de8          lea     ecx,[ebp-18h]
    6fb2cb98 894bfc          mov     dword ptr [ebx-4],ecx
    6fb2cb9b 8b5b0c          mov     ebx,dword ptr [ebx+0Ch]
    6fb2cb9e 8945e8          mov     dword ptr [ebp-18h],eax
    6fb2cba1 8b4518          mov     eax,dword ptr [ebp+18h]
    6fb2cba4 8945ec          mov     dword ptr [ebp-14h],eax
    6fb2cba7 83fbfe          cmp     ebx,0FFFFFFFEh
    6fb2cbaa 7458            je      MSVCR100!_except_handler4_common+0xc8 (6fb2cc04)
    6fb2cbac 8d145b          lea     edx,[ebx+ebx*2]
    6fb2cbaf 8b4c9614        mov     ecx,dword ptr [esi+edx*4+14h]
    6fb2cbb3 8d449610        lea     eax,[esi+edx*4+10h]
    6fb2cbb7 8945f0          mov     dword ptr [ebp-10h],eax
    6fb2cbba 8b00            mov     eax,dword ptr [eax]
    6fb2cbbc 8945f8          mov     dword ptr [ebp-8],eax
    6fb2cbbf 85c9            test    ecx,ecx
    6fb2cbc1 7414            je      MSVCR100!_except_handler4_common+0x9b (6fb2cbd7)
    6fb2cbc3 8bd7            mov     edx,edi
    6fb2cbc5 e89863f7ff      call    MSVCR100!_EH4_CallFilterFunc (6faa2f62)  //调用进去会相应的调用OnExceptionOccuered
    6fb2cbca c645ff01        mov     byte ptr [ebp-1],1
    6fb2cbce 85c0            test    eax,eax
    6fb2cbd0 783c            js      MSVCR100!_except_handler4_common+0xd2 (6fb2cc0e)
    6fb2cbd2 7f43            jg      MSVCR100!_except_handler4_common+0xdb (6fb2cc17)
    6fb2cbd4 8b45f8          mov     eax,dword ptr [ebp-8]
    6fb2cbd9 83f8fe          cmp     eax,0FFFFFFFEh
    6fb2cbdc 75ce            jne     MSVCR100!_except_handler4_common+0x70 (6fb2cbac)
    6fb2cbde 807dff00        cmp     byte ptr [ebp-1],0
    6fb2cbe2 7420            je      MSVCR100!_except_handler4_common+0xc8 (6fb2cc04)
    6fb2cbe4 8b06            mov     eax,dword ptr [esi]
    6fb2cbe6 83f8fe          cmp     eax,0FFFFFFFEh
    6fb2cbe9 740b            je      MSVCR100!_except_handler4_common+0xba (6fb2cbf6)
    6fb2cbeb 8b4e04          mov     ecx,dword ptr [esi+4]
    6fb2cbee 03cf            add     ecx,edi
    6fb2cbf0 330c38          xor     ecx,dword ptr [eax+edi]
    6fb2cbf3 ff550c          call    dword ptr [ebp+0Ch]
    6fb2cbf6 8b4e0c          mov     ecx,dword ptr [esi+0Ch]
    6fb2cbf9 8b5608          mov     edx,dword ptr [esi+8]
    6fb2cbfc 03cf            add     ecx,edi
    6fb2cbfe 330c3a          xor     ecx,dword ptr [edx+edi]
    6fb2cc01 ff550c          call    dword ptr [ebp+0Ch]
    6fb2cc04 8b45f4          mov     eax,dword ptr [ebp-0Ch]
    6fb2cc07 5f              pop     edi
    6fb2cc08 5e              pop     esi
    6fb2cc09 5b              pop     ebx
    6fb2cc0a 8be5            mov     esp,ebp
    6fb2cc0c 5d              pop     ebp
    6fb2cc0d c3              ret
    

    调用OnExceptionOccuered之后再度抛出异常

    00e5f1fc 771d6457 ntdll!RtlDispatchException+0xec
    00e5f1fc 75219617 ntdll!KiUserExceptionDispatcher+0xf
    00e5f568 6fac7819 KERNELBASE!RaiseException+0x58
    00e5f5a0 0136105f MSVCR100!_CxxThrowException+0x48 [f:\dd\vctools\crt_bld\self_x86\crt\prebuild\eh\throw.cpp @ 157]
    00e5f5e8 013611ae Win32ExRes!OnExceptionOccuered+0x5f [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 21]
    00e5fc5c 01361205 Win32ExRes!CPPExceptionTest+0xee [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 53]
    00e5fc60 75cc1174 Win32ExRes!ThreadProc+0x5 [e:\project\demo\c+\exception_res\win32exres\win32exres\win32exres.cpp @ 75]
    00e5fc6c 771eb3f5 kernel32!BaseThreadInitThunk+0xe
    00e5fcac 771eb3c8 ntdll!__RtlUserThreadStart+0x70
    00e5fcc4 00000000 ntdll!_RtlUserThreadStart+0x1b
    

    RtlDispatchException内部 

    call    ntdll!RtlpGetRegistrationHead (771d672f)  

    对_EXCEPTION_REGISTRATION_RECORD进行遍历处理相应的调用handler进行处理

      

      

      

      

      

      

      

      

  • 相关阅读:
    Postman-插入断言
    浅谈如何提高自动化测试的稳定性和可维护性 (pytest&allure)
    pytest+allure+jenkins-持续集成平台生成allure报告
    pytest简介及入门
    allure描述用例详细讲解
    allure标记用例级别severity
    allure-pytest 功能用例与自动化用例完美对接
    allure-pytest 环境准备和初步运行
    selenium常用操作之上传操作
    selenium常用操作之JS处理日历控件
  • 原文地址:https://www.cnblogs.com/SkyMouse/p/2535474.html
Copyright © 2011-2022 走看看