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進行處理

 

  

  

  

  

  

  

  

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM