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进行处理