Part1
Below is the test code I am using:
#include<stdio.h>
#include<windows.h>
void main()
{
__try
{
int i=1;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("EXCEPTION_EXECUTE_HANDLER\n");
}
getchar();
}
Debug-mode Prolog:
void main()
{
00411A50 push ebp
00411A51 mov ebp,esp //setting up the stack frame for main
00411A53 push 0FFFFFFFFh //_EXCEPTION_REGISTRATION.trylevel=-1;
00411A55 push 425070h //_EXCEPTION_REGISTRATION.scopetable=425070h;(note#1)
00411A5A push offset @ILT+375(__except_handler3)(41117Ch)
//_EXCEPTION_REGISTRATION.handler=__except_handler3;
00411A5F mov eax,dword ptr fs:[00000000h]
00411A65 push eax //_EXCEPTION_REGISTRATION.prev=dword ptr fs:[00000000h];
00411A66 mov dword ptr fs:[0],esp //dword ptr fs:[00000000h]=esp
00411A6D add esp,0FFFFFF28h
00411A73 push ebx
00411A74 push esi
00411A75 push edi
00411A76 lea edi,[ebp-0E8h]
00411A7C mov ecx,34h
00411A81 mov eax,0CCCCCCCCh
00411A86 rep stos dword ptr [edi]
00411A88 mov dword ptr [ebp-18h],esp //store the current esp in [ebp-18h];(note#2)
Note:
1. in windbg, we can use "dd 425070h l3". We will get:
00425070: ffffffff 00411aa2 00411aa8
Comparing with SCOPETABLE prototype below:
typedef struct _SCOPETABLE
{
DWORD previousTryLevel;
DWORD lpfnFilter
DWORD lpfnHandler
} SCOPETABLE, *PSCOPETABLE;
We know that:
PSCOPETABLE[0].previousTryLevel=-1
PSCOPETABLE[0].lpfnFilter=00411aa2
PSCOPETABLE[0].lpfnHandler=00411aa8
By using "uf 00411aa2", we got:
10 00411aa2 b801000000 mov eax,0x1
10 00411aa7 c3 ret
that is what "__except(EXCEPTION_EXECUTE_HANDLER)" is generated by VC.
Regarding "00411aa8", we can get the following from VS.net:
00411AA8 mov esp,dword ptr [ebp-18h]
//before executing the exception handler, we restore the ESP with original stored value(in [ebp-18h]
{
printf("EXCEPTION_EXECUTE_HANDLER\n");
00411AAB push offset string "I have catched int 3 exception\n" (42501Ch)
00411AB0 call @ILT+1185(_printf) (4114A6h)
00411AB5 add esp,4
00411AB8 mov dword ptr [ebp-4],0FFFFFFFFh
//restore the _EXCEPTION_REGISTRATION.trylevel to -1(note#2)
}
As we can see, lpfnHandler points to the code snippet that never returns back to its caller(_except_handler3)
2. Just 2 DWORD below the _EXCEPTION_REGISTRATION, this is where we store the original ESP.
The saved ESP point to the stack top where all the local variables and buffers and saved registers are pushed on to the stack.
Part2
__try
00411A8B mov dword ptr [ebp-4],0
{
int i=1;
00411A92 mov dword ptr [i],1
00411A99 mov dword ptr [ebp-4],0FFFFFFFFh
00411AA0 jmp $L55563+17h (411ABFh)
}
As we can see, before entering the __try block, compiler will set _EXCEPTION_REGISTRATION.trylevel to 0, and before exiting the __try block, compiler will retore it to -1.
If we exiting the __try block normally without any exception from generating, compiler uses jmp to goto the next instructor after __except block.