We are all familiar with try - except constructs from C++ (or Java, etc.) code and we all know what this construct is used for. However, I will try to take us deeper into the exception handling mechanism in this post.
Structured Exception Handling aka SEHThe MSDN definition of SEH is "Structured exception handling is a mechanism for handling both hardware and software exceptions. Therefore, your code will handle hardware and software exceptions identically. Structured exception handling enables you to have complete control over the handling of exceptions, provides support for debuggers, and is usable across all programming languages and machines." We will not cover hardware exceptions here, instead we are going to see how the software side is implemented.
SEH is based on frames. Each frame represents an instance of EXCEPTION_REGISTRATION structure and has the following format:
struct _EXCEPTION_REGISTRATION* prev;
} EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION;
where prev is a pointer to previously defined Exception Registration and handler is a pointer to exception handler - a function that is invoked when exception occurs. Due to the nature of SEH, when you register an exception handler within a function, you have to unregister it before you leave that function. However, you do not have to bother yourself with this if you are writing in high level language such as C++. In this case all these operations are inserted by the compiler and are totally transparent to you - the developer.
If you ever took a look at a function that uses exception handling in disassembler, you probably saw something like this:
push dword [FS:0]
mov [FS:0], ESP
This is exactly how EXCEPTION_REGISTRATION frames are created. The first thing is to store the address of the function we want to be called when an exception occurs (pointer_to_exception_handler). This address is stored on stack. The next step - we store the address of current record. [FS:0] points to the beginning of the TIB (Thread Information Block) structure, where the first cell contains the address of the latest exception registration record added. Finally, we have to store the address of the exception registration record we have recently added. As it has been already mentioned, the address of the topmost EXCEPTION_REGISTRATION structure is stored at [FS:0], thus, as our ESP register points exactly at it, we simply move it to [FS:0].
We are done. Now our function is the first that would gain control should in case of exception.
The following set of operations removes the topmost EXCEPTION_REGISTRATION record from the chain:
pop dword [FS:0]
add ESP, 4
Exception HandlerException Handler is an application defined function/code (unless the handler resides in one of the loaded DLLs, in which case it is not defined by the application) which is intended to fix the situation that lead to exception, if possible. In most cases, such function would simply abort the operation that raised the exception. The definition of such function should be as follows:
ExceptionHandler(__in PEXCEPTION_POINTERS ExceptionInformation);
where PEXCEPTION_POINTERS is a pointer to EXCEPTION_POINTERS structure which, in turn, contains all the information about the exception and the state of the process at the time of exception. The fields are pointers to EXCEPTION_RECORD and CONTEXT structures respectively. The following is the declaration of the EXCEPTION_POINTERS structure:
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
ExceptionRecord describes the exception that was raised and caused the invocation of our handler. It contains the following data:
struct _EXCEPTION_RECORD* ExceptionRecord;
} EXCEPTION_RECORD, *PEXCEPTION_RECORD;
You may find the full description of this structure here.
ContextRecord is much more interesting as it provides us with fill description of the state of the process right at the moment the exception was raised. It is relatively hard to find its detailed description on the internet, although, MSDN provides us with some information. In either case, here is the declaration of this structure as I use it in my assembly code (FASM syntax):
.ContextFlags dd ? ;0x00
.Dr0 dd ? ;0x04
.Dr1 dd ? ;0x08
.Dr2 dd ? ;0x0C
.Dr3 dd ? ;0x10
.Dr6 dd ? ;0x14
.Dr7 dd ? ;0x18
.FloatSave FLOATING_SAVE_AREA ;0x1C
.SegGs dd ? ;0x8C
.SegFs dd ? ;0x90
.SegEs dd ? ;0x94
.SegDs dd ? ;0x98
;General purpose registers
.Edi dd ? ;0x9C
.Esi dd ? ;0xA0
.Ebx dd ? ;0xA4
.Edx dd ? ;0xA8
.Ecx dd ? ;0xAC
.Eax dd ? ;0xB0
.Ebp dd ? ;0xB4
.Eip dd ? ;0xB8
.SegCs dd ? ;0xBC
.EFlags dd ? ;0xC0
.Esp dd ? ;0xC4
;Stack segment register
.SegSs dd ? ;0xC8
It, somehow, appears to be that it is even harder to find the description of the FLOATING_SAVE_AREA structure then the description of CONTEXT structure, but our will is our limit, so here is the declaration of FLOATING_SAVE_AREA too:
.ControlWord dd ? ;0x00
.StatusWord dd ? ;0x04
.TagWord dd ? ;0x08
.ErrorOffset dd ? ;0x0C
.ErrorSelector dd ? ;0x10
.DataOffset dd ? ;0x14
.DataSelector dd ? ;0x18
.RegisterArea rb 80 ;0x1C
.Cr0NpxState dd ? ;0x6C
But let us get back to the CONTEXT structure. It not only provides us with a clear picture of what is going on in the process, but also represents a powerful tool for us to manipulate the environment. For instance, we may alter the content of the EIP register and this would cause the program to continue from a different place when it gains control again. We can check whether our program is being debugged by checking the values of debug registers (a well known anti-debugging trick) and so on.
Once we are done with our handler, we should return one of the following values:
EXCEPTION_CONTINUE_SEARCH (0x0) //this, in turn, would signal the operating system that the exception has not been handled by this handler and it should try other handlers in the chain.
Vectored Exception Handling
Vectored Exception Handling is defined as an extension to SEH. One major difference is that when we register a vectored handler it is intact throughout the whole process, unlike structured exception handler which may only be used within a single function.
Unlike SEH, we do not have to manipulate stack or deal with memory allocations, or whatsoever. If we want to add a vectored exception handler we should simply call the AddVectoredExceptionHandler function:
AddVectoredExceptionHandler(__in ULONG FirstHandler, __in PVECTORED_EXCEPTION_HANDLER VectoredHandler );
or RemoveVectoredExceptionHandler function to remove it:
RemoveVectoredExceptionHandler( __in PVOID Handler );
The AddVectoredExceptionHandler function returns the handle (or NULL if it failed) to our handler and accepts the following parameters:
FirstHandler - if this parameter is not zero, then our handler is the first handler to be called or the last otherwise.
VectoredHandler - the address of our handler.
When removing our handler we call the RemoveVectoredExceptionHandler function passing the previously obtained handle as a parameter.
The rest is very similar to SEH except one tiny important thing - although, SEH and VEH handlers accept the same parameter (at least according to their declarations) it is not how it really works.
In case of SEH, the handler receives the pointer to EXCEPTION_POINTERS structure, whereas in case of VEH, the handler receives the EXCEPTION_POINTERS structure itself on the stack. Let me show it by a simple example:
0x0006FAA4 0x0006FAB0 ;pointer to EXCEPTION_RECORD structure
0x0006FAA8 0x0006FC00 ;pointer to CONTEXT structure
0x0006FAA4 0x0006FC00 ;pointer to CONTEXT structure
It appears to be that the underlying logic of exception handling in Windows is quite interesting and even more than that, it provides us with additional powerful tools. Being a reverse engineer for the most of my career, I have found that this mechanism provides developers with one of the most basic yet powerful anti-debugging abilities, which are often underestimated.
Hope this post was helpful. See you at the next post!