撕开编译器给throw套上的那层皮——代码还原
class MyBaseException{public:MyBaseException(){std::cout<<"BaseException"<<std::endl;}};class MyException:public MyBaseException{private:int m_a;int m_b;int m_c;char m_name[100];public:MyException(const char * str,int a,int b,int c){strcpy_s(m_name,100,str);m_a = a;m_b = b;m_c = c;}int get_a(){return m_a;}virtual int get_b(){return m_b;}virtual int get_c(){return m_c;}virtual char * get_name(){return m_name;}};int main(){throw MyException("exception_demo",1,2,3);return 0;}
0:000> .exr -1Last event was not an exception0:000> .ecxrUnable to get exception context, HRESULT 0x8000FFFF
0:000> kb# ChildEBP RetAddr Args to Child00 00fff3d0 76f314ad ffffffff 00000003 00000000 ntdll!NtTerminateProcess+0xc01 00fff4a8 75725902 00000003 77e8f3b0 ffffffff ntdll!RtlExitUserProcess+0xbd02 00fff4bc 715e7997 00000003 00fff50c 715e7ab0 KERNEL32!ExitProcessImplementation+0x1203 00fff4c8 715e7aaf 00000003 30b17962 00000000 MSVCR100!__crtExitProcess+0x1704 00fff50c 7161bf47 00000003 00000001 00000000 MSVCR100!doexit+0xfb05 00fff520 7164d707 00000003 7164383d 30b17936 MSVCR100!_exit+0x1106 00fff528 7164383d 30b17936 00000000 00000000 MSVCR100!abort+0x3207 00fff558 00911897 00fff5fc 7664ba90 00fff62c MSVCR100!terminate+0x3308 00fff560 7664ba90 00fff62c 255e6b41 00000000 test!__CxxUnhandledExceptionFilter+0x3c09 00fff5fc 76f829b8 00fff62c 76f563d2 00fffe60 KERNELBASE!UnhandledExceptionFilter+0x1a00a 00fffe60 76f47bf4 ffffffff 76f68ff3 00000000 ntdll!__RtlUserThreadStart+0x3adc30b 00fffe70 00000000 00911684 01191000 00000000 ntdll!_RtlUserThreadStart+0x1b
LONG UnhandledExceptionFilter( _EXCEPTION_POINTERS *ExceptionInfo );typedef struct _EXCEPTION_POINTERS{PEXCEPTION_RECORD ExceptionRecord;PCONTEXT ContextRecord;} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-unhandledexceptionfilter
0:000:x86> dt _EXCEPTION_POINTERS 00fff62cmsvcr100!_EXCEPTION_POINTERS+0x000 ExceptionRecord : 0x00fff768 _EXCEPTION_RECORD+0x004 ContextRecord : 0x00fff7b8 _CONTEXT0:000:x86> dt _EXCEPTION_RECORD 0x00fff768msvcr100!_EXCEPTION_RECORD+0x000 ExceptionCode : 0xe06d7363+0x004 ExceptionFlags : 1+0x008 ExceptionRecord : (null)+0x00c ExceptionAddress : 0x765b4402 Void+0x010 NumberParameters : 3+0x014 ExceptionInformation : [15] 0x199305200:000:x86> dt _CONTEXT 0x00fff7b8msvcr100!_CONTEXT+0x000 ContextFlags : 0x1007f+0x004 Dr0 : 0+0x008 Dr1 : 0+0x00c Dr2 : 0+0x010 Dr3 : 0+0x014 Dr6 : 0+0x018 Dr7 : 0+0x01c FloatSave : _FLOATING_SAVE_AREA+0x08c SegGs : 0x2b+0x090 SegFs : 0x53+0x094 SegEs : 0x2b+0x098 SegDs : 0x2b+0x09c Edi : 0x9133d4+0x0a0 Esi : 1+0x0a4 Ebx : 0+0x0a8 Edx : 0+0x0ac Ecx : 3+0x0b0 Eax : 0xfffc98+0x0b4 Ebp : 0xfffcf0+0x0b8 Eip : 0x765b4402+0x0bc SegCs : 0x23+0x0c0 EFlags : 0x212+0x0c4 Esp : 0xfffc98+0x0c8 SegSs : 0x2b+0x0cc ExtendedRegisters : [512]
0:000:x86> .exptr 00fff62cException record at 00fff768:ExceptionAddress: 765b4402 (KERNELBASE!RaiseException+0x00000062)ExceptionCode: e06d7363 (C++ EH exception)ExceptionFlags: 00000001NumberParameters: 3: 19930520: 00fffd38: 00912400pExceptionObject: 00fffd38_s_ThrowInfo : 00912400Type : class MyExceptionType : class MyBaseExceptionContext record at 00fff7b8:eax=00fffc98 ebx=00000000 ecx=00000003 edx=00000000 esi=00000001 edi=009133d4eip=765b4402 esp=00fffc98 ebp=00fffcf0 iopl=0 nv up ei pl nz ac po nccs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000212:765b4402 8b4c2454 mov ecx,dword ptr [esp+54h] ss:002b:00fffcec=255e6225
0:000:x86> .formats e06d7363Evaluate expression:Hex: e06d7363Decimal: -529697949Octal: 34033271543Binary: 11100000 01101101 01110011 01100011Chars: .mscTime: ***** InvalidFloat: low -6.84405e+019 high 0Double: 1.86029e-314
MyException("exception_demo",1,2,3);省略00911078 6800249100 push offset test+0x2400 (00912400)0091107d 8d4588 lea eax,[ebp-78h] //这个是MyException栈对象的地址00911080 50 push eax00911081 c7458c01000000 mov dword ptr [ebp-74h],100911088 c7459002000000 mov dword ptr [ebp-70h],20091108f c7459403000000 mov dword ptr [ebp-6Ch],300911096 e8050c0000 call test+0x1ca0 (00911ca0) //根据
0:000:x86> uf _CxxThrowException715e86e8 8bff mov edi,edi715e86ea 55 push ebp715e86eb 8bec mov ebp,esp715e86ed 83ec20 sub esp,20h715e86f0 8b4508 mov eax,dword ptr [ebp+8] ;arg1715e86f3 56 push esi715e86f4 57 push edi715e86f5 6a08 push 8715e86f7 59 pop ecx715e86f8 be34875e71 mov esi,offset msvcr100!ExceptionTemplate (715e8734) ;下边有dmp出这块内存的数据715e86fd 8d7de0 lea edi,[ebp-20h]715e8700 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] ;从ExceptionTemplate中拷贝8*4=0x20字节的数据715e8702 8945f8 mov dword ptr [ebp-8],eax ;用arg1替代从ExceptionTemplate中拷贝过来的对应偏移的数据715e8705 8b450c mov eax,dword ptr [ebp+0Ch] ;arg2715e8708 5f pop edi715e8709 8945fc mov dword ptr [ebp-4],eax ;用arg2替代从ExceptionTemplate中拷贝过来的对应偏移的数据715e870c 5e pop esi715e870d 85c0 test eax,eax715e870f 7409 je msvcr100!_CxxThrowException+0x35 (715e871a)715e8711 f60008 test byte ptr [eax],8715e8714 0f856a440100 jne msvcr100!_CxxThrowException+0x2e (715fcb84)715e871a 8d45f4 lea eax,[ebp-0Ch]715e871d 50 push eax ;lpArguments715e871e ff75f0 push dword ptr [ebp-10h] ;nNumberOfArguments715e8721 ff75e4 push dword ptr [ebp-1Ch] ;dwExceptionFlags715e8724 ff75e0 push dword ptr [ebp-20h] ;dwExceptionCode715e8727 ff1508105c71 call dword ptr [msvcr100!_imp__RaiseException (715c1008)]715e872d c9 leave715e872e c20800 ret 8715fcb84 c745f400409901 mov dword ptr [ebp-0Ch],1994000h715fcb8b e98abbfeff jmp msvcr100!_CxxThrowException+0x35 (715e871a)0:000:x86> dd 715e8734 l8715e8734 e06d7363 00000001 00000000 00000000715e8744 00000003 19930520 00000000 00000000
struct ExceptionTemplate{DWORD dwExceptionCode ;e06d7363 ---- .mscDWORD dwExceptionFlags ;00000001DWORD xxxx_0 ;00000000DWORD xxxx_0 ;00000000DWORD nNumberOfArguments ;00000003DWORD lpArguments[3] ;19930520 00000000 00000000}
arg1为throw后边的异常对象的地址----这个可直接从上边的函数调用中推测出来;arg2为_s_ThrowInfo对象的地址----这个是从.exptr给出的结论中推测出来的;_CxxThrowException(ExceptionObject *arg1,s_ThrowInfo *arg2){struct ExceptionTemplate temp = msvcr100!ExceptionTemplate;temp.lpArguments[1] = arg1;temp.lpArguments[2] = arg2;if(*(DWORD*)arg2 & 8){temp.lpArguments[0]=0x1994000}return RaiseException(temp.dwExceptionCode, temp.dwExceptionFlags,temp.nNumberOfArguments,temp. lpArguments);}
0:000:x86> dd 00fffd3800fffd38 00912150 00000001 00000002 0000000300fffd48 65637865 6f697470 65645f6e 00006f6d00fffd58 000000000:000:x86> da 00fffd4800fffd48 "exception_demo"0:000:x86> dps 0091215000912150 00911000 test+0x100000912154 00911010 test+0x101000912158 00911020 test+0x10200091215c 00000000
0:000:x86> dt _s_ThrowInfo 00912400msvcr100!_s_ThrowInfoattributes : 0pmfnUnwind : (null)pForwardCompat : (null)pCatchableTypeArray : 0x009123f4 _s_CatchableTypeArray0:000:x86> dt _s_CatchableTypeArray 0x009123f4msvcr100!_s_CatchableTypeArraynCatchableTypes : 0n2arrayOfCatchableTypes : [0] 0x009123bc _s_CatchableType0:000:x86> dd 0x009123f4 l3009123f4 00000002 009123bc 009123d80:000:x86> dt 0x009123bc _s_CatchableTypemsvcr100!_s_CatchableTypeproperties : 0pType : 0x00913038 TypeDescriptorthisDisplacement : PMDsizeOrOffset : 0n116copyFunction : 0x009110a0 void +00:000:x86> dt 0x00913038 _TypeDescriptormsvcr100!_TypeDescriptorpVFTable : 0x00912120 Voidspare : (null)name : [0] ".?AVMyException@@"0:000:x86> dt 009123d8 _s_CatchableTypemsvcr100!_s_CatchableTypeproperties : 0pType : 0x00913054 TypeDescriptorthisDisplacement : PMDsizeOrOffset : 0n1copyFunction : (null)0:000:x86> dt 0x00913054 _TypeDescriptormsvcr100!_TypeDescriptorpVFTable : 0x00912120 Voidspare : (null)name : [0] ".?AVMyBaseException@@"第一处的copyFunction后边有个地址,我看反汇编看一下里边的内容:0:000:x86> u 009110a0 l20:009110a0 55 push ebp009110a1 8bec mov ebp,esp009110a3 8bc1 mov eax,ecx009110a5 8b4d08 mov ecx,dword ptr [ebp+8]009110a8 c70050219100 mov dword ptr [eax],offset test+0x2150 (00912150)009110ae 8b5104 mov edx,dword ptr [ecx+4]009110b1 56 push esi009110b2 895004 mov dword ptr [eax+4],edx009110b5 8b5108 mov edx,dword ptr [ecx+8]009110b8 57 push edi009110b9 895008 mov dword ptr [eax+8],edx009110bc 8b510c mov edx,dword ptr [ecx+0Ch]009110bf 8d7110 lea esi,[ecx+10h]009110c2 8d7810 lea edi,[eax+10h]009110c5 b919000000 mov ecx,19h009110ca 89500c mov dword ptr [eax+0Ch],edx009110cd f3a5 rep movs dword ptr es:[edi],dword ptr [esi]009110cf 5f pop edi009110d0 5e pop esi009110d1 5d pop ebp009110d2 c20400 ret 4
很多情况下,拿到dmp进行栈回溯,只有一行,这便是栈回溯失败的例子,不要担心,看见e06d7363你就知道这是个C++异常了。简单查看下内存数据就得到ExceptionTemplate了;
0:000:x86> dd 00fffcf000fffcf0 00fffd28 715e872d e06d7363 0000000100fffd00 00000003 00fffd1c e06d7363 0000000100fffd10 00000000 00000000 00000003 1993052000fffd20 00fffd38 00912400 00fffdb0 0091109b00fffd30 00fffd38 00912400 00912150 0000000100fffd40 00000002 00000003 65637865 6f69747000fffd50 65645f6e 00006f6d 00000000 00fffd8800fffd60 715dd1af 019d392c 019d3981 00fffd80
0:000:x86> !cppexr 00fffd08pExceptionObject: 00fffd38_s_ThrowInfo : 00912400Type : class MyExceptionType : class MyBaseException
觉得内容不错就点个“在看”吧!
