撕开编译器给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 -1
Last event was not an exception
0:000> .ecxr
Unable to get exception context, HRESULT 0x8000FFFF
0:000> kb
# ChildEBP RetAddr Args to Child
00 00fff3d0 76f314ad ffffffff 00000003 00000000 ntdll!NtTerminateProcess+0xc
01 00fff4a8 75725902 00000003 77e8f3b0 ffffffff ntdll!RtlExitUserProcess+0xbd
02 00fff4bc 715e7997 00000003 00fff50c 715e7ab0 KERNEL32!ExitProcessImplementation+0x12
03 00fff4c8 715e7aaf 00000003 30b17962 00000000 MSVCR100!__crtExitProcess+0x17
04 00fff50c 7161bf47 00000003 00000001 00000000 MSVCR100!doexit+0xfb
05 00fff520 7164d707 00000003 7164383d 30b17936 MSVCR100!_exit+0x11
06 00fff528 7164383d 30b17936 00000000 00000000 MSVCR100!abort+0x32
07 00fff558 00911897 00fff5fc 7664ba90 00fff62c MSVCR100!terminate+0x33
08 00fff560 7664ba90 00fff62c 255e6b41 00000000 test!__CxxUnhandledExceptionFilter+0x3c
09 00fff5fc 76f829b8 00fff62c 76f563d2 00fffe60 KERNELBASE!UnhandledExceptionFilter+0x1a0
0a 00fffe60 76f47bf4 ffffffff 76f68ff3 00000000 ntdll!__RtlUserThreadStart+0x3adc3
0b 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 00fff62c
msvcr100!_EXCEPTION_POINTERS
+0x000 ExceptionRecord : 0x00fff768 _EXCEPTION_RECORD
+0x004 ContextRecord : 0x00fff7b8 _CONTEXT
0:000:x86> dt _EXCEPTION_RECORD 0x00fff768
msvcr100!_EXCEPTION_RECORD
+0x000 ExceptionCode : 0xe06d7363
+0x004 ExceptionFlags : 1
+0x008 ExceptionRecord : (null)
+0x00c ExceptionAddress : 0x765b4402 Void
+0x010 NumberParameters : 3
+0x014 ExceptionInformation : [15] 0x19930520
0:000:x86> dt _CONTEXT 0x00fff7b8
msvcr100!_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 00fff62c
Exception record at 00fff768:
ExceptionAddress: 765b4402 (KERNELBASE!RaiseException+0x00000062)
ExceptionCode: e06d7363 (C++ EH exception)
ExceptionFlags: 00000001
NumberParameters: 3
19930520 :
00fffd38 :
00912400 :
pExceptionObject: 00fffd38
_s_ThrowInfo : 00912400
Type : class MyException
Type : class MyBaseException
Context record at 00fff7b8:
eax=00fffc98 ebx=00000000 ecx=00000003 edx=00000000 esi=00000001 edi=009133d4
eip=765b4402 esp=00fffc98 ebp=00fffcf0 iopl=0 nv up ei pl nz ac po nc
cs=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 e06d7363
Evaluate expression:
Hex: e06d7363
Decimal: -529697949
Octal: 34033271543
Binary: 11100000 01101101 01110011 01100011
Chars: .msc
Time: ***** Invalid
Float: low -6.84405e+019 high 0
Double: 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 eax
00911081 c7458c01000000 mov dword ptr [ebp-74h],1
00911088 c7459002000000 mov dword ptr [ebp-70h],2
0091108f c7459403000000 mov dword ptr [ebp-6Ch],3
00911096 e8050c0000 call test+0x1ca0 (00911ca0) //根据
0:000:x86> uf _CxxThrowException
715e86e8 8bff mov edi,edi
715e86ea 55 push ebp
715e86eb 8bec mov ebp,esp
715e86ed 83ec20 sub esp,20h
715e86f0 8b4508 mov eax,dword ptr [ebp+8] ;arg1
715e86f3 56 push esi
715e86f4 57 push edi
715e86f5 6a08 push 8
715e86f7 59 pop ecx
715e86f8 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] ;arg2
715e8708 5f pop edi
715e8709 8945fc mov dword ptr [ebp-4],eax ;用arg2替代从ExceptionTemplate中拷贝过来的对应偏移的数据
715e870c 5e pop esi
715e870d 85c0 test eax,eax
715e870f 7409 je msvcr100!_CxxThrowException+0x35 (715e871a)
715e8711 f60008 test byte ptr [eax],8
715e8714 0f856a440100 jne msvcr100!_CxxThrowException+0x2e (715fcb84)
715e871a 8d45f4 lea eax,[ebp-0Ch]
715e871d 50 push eax ;lpArguments
715e871e ff75f0 push dword ptr [ebp-10h] ;nNumberOfArguments
715e8721 ff75e4 push dword ptr [ebp-1Ch] ;dwExceptionFlags
715e8724 ff75e0 push dword ptr [ebp-20h] ;dwExceptionCode
715e8727 ff1508105c71 call dword ptr [msvcr100!_imp__RaiseException (715c1008)]
715e872d c9 leave
715e872e c20800 ret 8
715fcb84 c745f400409901 mov dword ptr [ebp-0Ch],1994000h
715fcb8b e98abbfeff jmp msvcr100!_CxxThrowException+0x35 (715e871a)
0:000:x86> dd 715e8734 l8
715e8734 e06d7363 00000001 00000000 00000000
715e8744 00000003 19930520 00000000 00000000
struct ExceptionTemplate
{
DWORD dwExceptionCode ;e06d7363 ---- .msc
DWORD dwExceptionFlags ;00000001
DWORD xxxx_0 ;00000000
DWORD xxxx_0 ;00000000
DWORD nNumberOfArguments ;00000003
DWORD 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 00fffd38
00fffd38 00912150 00000001 00000002 00000003
00fffd48 65637865 6f697470 65645f6e 00006f6d
00fffd58 00000000
0:000:x86> da 00fffd48
00fffd48 "exception_demo"
0:000:x86> dps 00912150
00912150 00911000 test+0x1000
00912154 00911010 test+0x1010
00912158 00911020 test+0x1020
0091215c 00000000
0:000:x86> dt _s_ThrowInfo 00912400
msvcr100!_s_ThrowInfo
attributes : 0
pmfnUnwind : (null)
pForwardCompat : (null)
pCatchableTypeArray : 0x009123f4 _s_CatchableTypeArray
0:000:x86> dt _s_CatchableTypeArray 0x009123f4
msvcr100!_s_CatchableTypeArray
nCatchableTypes : 0n2
arrayOfCatchableTypes : [0] 0x009123bc _s_CatchableType
0:000:x86> dd 0x009123f4 l3
009123f4 00000002 009123bc 009123d8
0:000:x86> dt 0x009123bc _s_CatchableType
msvcr100!_s_CatchableType
properties : 0
pType : 0x00913038 TypeDescriptor
thisDisplacement : PMD
sizeOrOffset : 0n116
copyFunction : 0x009110a0 void +0
0:000:x86> dt 0x00913038 _TypeDescriptor
msvcr100!_TypeDescriptor
pVFTable : 0x00912120 Void
spare : (null)
name : [0] ".?AVMyException@@"
0:000:x86> dt 009123d8 _s_CatchableType
msvcr100!_s_CatchableType
properties : 0
pType : 0x00913054 TypeDescriptor
thisDisplacement : PMD
sizeOrOffset : 0n1
copyFunction : (null)
0:000:x86> dt 0x00913054 _TypeDescriptor
msvcr100!_TypeDescriptor
pVFTable : 0x00912120 Void
spare : (null)
name : [0] ".?AVMyBaseException@@"
第一处的copyFunction后边有个地址,我看反汇编看一下里边的内容:
0:000:x86> u 009110a0 l20
:
009110a0 55 push ebp
009110a1 8bec mov ebp,esp
009110a3 8bc1 mov eax,ecx
009110a5 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 esi
009110b2 895004 mov dword ptr [eax+4],edx
009110b5 8b5108 mov edx,dword ptr [ecx+8]
009110b8 57 push edi
009110b9 895008 mov dword ptr [eax+8],edx
009110bc 8b510c mov edx,dword ptr [ecx+0Ch]
009110bf 8d7110 lea esi,[ecx+10h]
009110c2 8d7810 lea edi,[eax+10h]
009110c5 b919000000 mov ecx,19h
009110ca 89500c mov dword ptr [eax+0Ch],edx
009110cd f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
009110cf 5f pop edi
009110d0 5e pop esi
009110d1 5d pop ebp
009110d2 c20400 ret 4
很多情况下,拿到dmp进行栈回溯,只有一行,这便是栈回溯失败的例子,不要担心,看见e06d7363你就知道这是个C++异常了。简单查看下内存数据就得到ExceptionTemplate了;
0:000:x86> dd 00fffcf0
00fffcf0 00fffd28 715e872d e06d7363 00000001
00fffd00 00000003 00fffd1c e06d7363 00000001
00fffd10 00000000 00000000 00000003 19930520
00fffd20 00fffd38 00912400 00fffdb0 0091109b
00fffd30 00fffd38 00912400 00912150 00000001
00fffd40 00000002 00000003 65637865 6f697470
00fffd50 65645f6e 00006f6d 00000000 00fffd88
00fffd60 715dd1af 019d392c 019d3981 00fffd80
0:000:x86> !cppexr 00fffd08
pExceptionObject: 00fffd38
_s_ThrowInfo : 00912400
Type : class MyException
Type : class MyBaseException
觉得内容不错就点个“在看”吧!