Today I gonna dump some facts about Windows Structured Exception Handling (SEH) mechanism. This article is mostly based on This great article.
OK, some dry facts about exception handling in Windows:
- per thread
- FS:[0] (TIB first dword) points to the first EXCEPTION_REGISTRATION struct
_EXCEPTION_REGISTRATION structexcept_handler callback
prev dd ? // EXCEPTION_REGISTRATION linked list next record
handler dd ? // _except_ handler callback function pointer
_EXCEPTION_REGISTRATION ends
- can agree/decline to handle a given exception
- if declined, the system will continue looking for other exception handler
EXCEPTION_DISPOSITION __cdecl _except_handler(
struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord, // registers values when exception occured
void * DispatcherContext );
typedef struct _EXCEPTION_RECORDException handling flow:
{
DWORD ExceptionCode; // assigned by OS
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress; // where the exception occured
DWORD NumberParameters;
DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;
- Exception occurred
- The system walks the EXCEPTION_REGISTRATIONs linked list to find a hanlder
- when a handler agreed to handle the exception all the handlers before it are called again with flag EH_UNWINDING (to allow cleanups*)
* when handler declines handling an exception, control typically doesn't exit from the function normally - calling dtors and finally blocks - execution continues wherever the handling callback decides (with ebp, esp set by the handler)
- all things below the handling frame's stack region are "removed"
- EXCEPTION_REGISTRATIONs in the list prior to the one that handled the exception are removed from the list
- see step 11 in the above figure
- default OS supplied exception handler (terminate / debug dialog)
- always agrees to handle an exception
- if no debugger is installed, the default dialog you will see may be similar to this:
Visual C++ Compiler level SEH
- every EXCEPTION_REGISTRATION handler points to the same VC++ runtime lib function __except_handlerX
- only one EXCEPTION_REGISTRATION is created per function on the stack
The Extended Exception Handling Frame
EBP-00 _ebp
EBP-04 trylevel
EBP-08 scopetable pointer
EBP-0C handler function address
EBP-10 previous EXCEPTION_REGISTRATION
EBP-14 GetExceptionPointers // pointers to GetExceptionInformation, GetExceptionCode
EBP-18 Standard ESP in frame
struct _EXCEPTION_REGISTRATION{
struct _EXCEPTION_REGISTRATION *prev;
void (*handler)(PEXCEPTION_RECORD,
PEXCEPTION_REGISTRATION,
PCONTEXT,
PEXCEPTION_RECORD);
struct scopetable_entry *scopetable;
int trylevel; // index into scopetable
int _ebp; // ebp value before the EXCEPTION_REGISTRATION was created
PEXCEPTION_POINTERS xpointers;
};
typedef struct _SCOPETABLE
{
DWORD previousTryLevel; // the next level try block trylevel (most in -> out)
DWORD lpfnFilter
DWORD lpfnHandler
} SCOPETABLE, *PSCOPETABLE;
The main idea behind this technique is expressed in the following simple example:
void foo() { printf("code line #1\n"); printf("code line #2\n"); printf("code line #3\n"); }will become:
void foo() { try { // exception } catch(...) { printf("code line #1\n"); try { // exception } catch(...) { printf("code line #2\n"); try { // exception } catch(...) { printf("code line #3\n"); } } } }
No comments :
Post a Comment