1、_try _except自动挂入链表
手动挂入链表:
_asm{
mov eax, fs:[0]
mov temp, eax
lea ecx, myException
mov fs : [0], ecx
}
我们用上篇的简单测试代码下断点查看反汇编得到代码片段如下:
0040102A push offset __except_handler3 (00401320)
0040102F mov eax,fs:[00000000]
00401035 push eax
00401036 mov dword ptr fs:[0],esp
可见异常处理函数固定为_except_handler3 (00401320),编译器不同地址不同
2、_try _except嵌套,重复
每个使用_try _except的函数,不管内部嵌套或反复多次_try _except,只注册一遍,即只将一个_EXCEPTION_REGISTRATION_RECORD挂入当前线程的异常链表中(对于递归函数每一次调用都会创建_EXCEPTION_REGISTRATION_RECORD,并挂入线程的异常链表中)
typedef struct _EXCEPTION_REGISTRATION_RECORD{
struct _EXCEPTION_REGISTRATION_RECORD *Next;
PEXCEPTION_ROUTINE Handler;
}EXCEPTION_REGISTRATION_RECORD;
验证代码:
#include <windows.h>
#include <stdio.h>
void TestException()
{
_try{
_try{
}
_except(1){
}
}
_except(1){
}
_try{
}
_except(1){
}
}
int main()
{
TestException();
getchar();
return 0;
}
对应反汇编
4: void TestException()
5: {
00401020 push ebp
00401021 mov ebp,esp
00401023 push 0FFh
00401025 push offset string "_filbuf.c"+0FFFFFFD4h (00420020)
0040102A push offset __except_handler3 (0040127c)
0040102F mov eax,fs:[00000000]
00401035 push eax
00401036 mov dword ptr fs:[0],esp
0040103D add esp,0B8h
00401040 push ebx
00401041 push esi
00401042 push edi
00401043 mov dword ptr [ebp-18h],esp
00401046 lea edi,[ebp-58h]
00401049 mov ecx,10h
0040104E mov eax,0CCCCCCCCh
00401053 rep stos dword ptr [edi]
6: _try{
00401055 mov dword ptr [ebp-4],0
7: _try{
0040105C mov dword ptr [ebp-4],1
8:
9: }
00401063 mov dword ptr [ebp-4],0
0040106A jmp $L42199+0Ah (0040107c)
10: _except(1){
0040106C mov eax,1
$L42200:
00401071 ret
$L42199:
00401072 mov esp,dword ptr [ebp-18h]
11: }
00401075 mov dword ptr [ebp-4],0
12:
13: }
0040107C mov dword ptr [ebp-4],0FFFFFFFFh
00401083 jmp $L42195+0Ah (00401095)
14: _except(1){
00401085 mov eax,1
$L42196:
0040108A ret
$L42195:
0040108B mov esp,dword ptr [ebp-18h]
15: }
0040108E mov dword ptr [ebp-4],0FFFFFFFFh
16:
17: _try{
00401095 mov dword ptr [ebp-4],2
18:
19: }
0040109C mov dword ptr [ebp-4],0FFFFFFFFh
004010A3 jmp $L42203+0Ah (004010b5)
20: _except(1){
004010A5 mov eax,1
$L42204:
004010AA ret
$L42203:
004010AB mov esp,dword ptr [ebp-18h]
21: }
004010AE mov dword ptr [ebp-4],0FFFFFFFFh
22: }
004010B5 mov ecx,dword ptr [ebp-10h]
004010B8 mov dword ptr fs:[0],ecx
004010BF pop edi
004010C0 pop esi
004010C1 pop ebx
004010C2 mov esp,ebp
004010C4 pop ebp
004010C5 ret
从上可以看到就一次该了fs:[0],那他是怎么实现的直挂一次就能解决问题的
3、编译器拓展_EXCEPTION_REGISTRATION_RECORD结构体
struct _EXCEPTION_REGISTRATION{
struct _EXCEPTION_REGISTRATION *prev;
void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD);
struct scopetable_entry *scopetable;
int trylevel;
int _ebp;
};
4、堆栈中形成的_EXCEPTION_REGISTRATION结构体
对比下面汇编代码分析
00401020 push ebp
00401021 mov ebp,esp
00401023 push 0FFh
00401025 push offset string "_filbuf.c"+0FFFFFFD4h (00420020)
0040102A push offset __except_handler3 (0040127c)
0040102F mov eax,fs:[00000000]
00401035 push eax