SEH: Structured Exception Handler 结构化异常处理。 是windows的一个__try{}__except(){}异常处理机制。可以捕获系统异常,也可以用RaiseException()函数来抛出自定义异常
TEB:Thread Environment Block 线程环境块。 是一个用来记录线程运行状态的结构体,前4字节是SEH链表的起始地址,是一个栈地址,后4字节是第一个处理函数
例子:
栈add :[-1(0xFFFFFFFF)] #是SEH的结尾标志
栈add-4h:[except_handle_function1_address(0xXXXXXXXX)]
栈add-8h:[except_handle_function2_address(0xXXXXXXXX)]
栈add-Ch:#这个地址就是TEB首4字节存放的内容
security cookie:一个数,在函数开始时和ebp的值异或,结果被保存,函数退出前检查是否栈溢出,可以防止恶意修改ebp
ES:段寄存器
FS:标志段寄存器(windows指向TEB)
GS:全局段寄存器
GS:全局段寄存器
1、返回值是一个类
father get_father()
{
father fa;
fa.set_val3(0x10);
return fa;
}
father myfa = get_father();
00EC181E lea eax,[myfa]
00EC1821 push eax #局部类对象地址入栈
00EC1822 call get_father (0EC1181h)
00EC1827 add esp,4
father get_father()
{
00D814A0 push ebp
00D814A1 mov ebp,esp #保存esp
00D814A3 push 0FFFFFFFFh #构建SEH链表,-1是结尾 位置:ebp-4
#异常处理程序入栈,函数名是系统随机生成的 位置:ebp-8
00D814A5 push offset __ehhandler$?get_father@@YA?AVfather@@XZ (0D84D97h)
00D814AA mov eax,dword ptr fs:[00000000h] #把TEB里老的SEH放入eax
00D814B0 push eax #入栈 位置:ebp-0Ch
00D814B1 sub esp,0E4h #申请栈空间 执行后esp等于
ebp-F0h
00D814B7 push ebx
00D814B8 push esi
00D814B9 push edi
00D814BA lea edi,[ebp-0F0h] #把上面的地址给edi,和下3句一起初始化申请的栈
00D814C0 mov ecx,39h
00D814C5 mov eax,0CCCCCCCCh
00D814CA rep stos dword ptr es:[edi]
00D814CC mov eax,dword ptr [___security_cookie (0D8801Ch)] #获取安全cookie
00D814D1 xor eax,ebp
00D814D3 push eax #跟ebp异或后的值保存在栈里 ebp-100h
00D814D4 lea eax,[ebp-0Ch] #eax=ebp-0Ch
00D814D7 mov dword ptr fs:[00000000h],eax #把栈地址设置到TEB首4字节里
00D814DD mov dword ptr [ebp-0ECh],0 #用于判断的参数
father fa;
00D814E7 lea ecx,[ebp-20h] #类对象首地址
00D814EA call father::father (0D81078h) #调用构造函数
00D814EF mov dword ptr [ebp-4],1 #开启异常捕获
fa.set_val3(0x10);
00D814F6 push 10h #调用成员函数
00D814F8 lea ecx,[ebp-20h]
00D814FB call father::set_val3 (0D81037h)
return fa;
00D81500 lea eax,[ebp-20h]
00D81503 push eax #函数内类对象地址作为参数入栈
00D81504 mov ecx,dword ptr [ebp+8]
#调用myfa的构造 注意这个构造不是默认构造函数,而是复制构造函数
00D81507 call father::father (0D8101Eh)
00D8150C mov ecx,dword ptr [ebp-0ECh]
00D81512 or ecx,1
00D81515 mov dword ptr [ebp-0ECh],ecx #把[ebp-0ECh]的值置为一
00D8151B mov byte ptr [ebp-4],0 #关闭异常捕获
00D8151F lea ecx,[ebp-20h] #函数内部对象析构
00D81522 call father::~father (0D810CDh)
00D81527 mov eax,dword ptr [ebp+8] #返回值是myfa的地址
}
00EC1842 push edx #检查栈参数
00EC1843 mov ecx,ebp
00EC1845 push eax
00EC1846 lea edx,[ (0EC1868h)]
00EC184C call @ILT+155(@_RTC_CheckStackVars@8) (0EC10A0h)
00EC1851 pop eax
00EC1852 pop edx
00EC1853 pop edi
00EC1854 pop esi
00EC1855 pop ebx
00EC1856 add esp,0E4h
00EC185C cmp ebp,esp #检查栈esp
00EC185E call @ILT+350(__RTC_CheckEsp) (0EC1163h)
00EC1863 mov esp,ebp
00EC1865 pop ebp
00EC1866 ret
拷贝构造函数:
father::father:
00EC17AC mov eax,dword ptr [this] #this指针依旧是放在ecx里
00EC17AF mov ecx,dword ptr [__that] #__that指针是参数ebp+8
00EC17B2 mov edx,dword ptr [ecx+4]
00EC17B5 mov dword ptr [eax+4],edx
#总结:其实是把类地址当参数传进去,然后在函数里先构造一个,最后调用复制构造函数把成员值全部拷贝过来