Search This Blog

Loading...

Tuesday, October 4, 2011

Windows Structured and Vectored Exception Handling Mechanisms

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 SEH
The 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:


typedef struct _EXCEPTION_REGISTRATION
{
       struct _EXCEPTION_REGISTRATION*  prev;
       DWORD                            handler;
} 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 pointer_to_exception_handler
    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:


    mov ESP,[FS:0]     ;this should not be needed
    pop dword [FS:0]
    add ESP, 4


Exception Handler
Exception 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:


LONG CALLBACK  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:


typedef struct _EXCEPTION_POINTERS
{
       PEXCEPTION_RECORD  ExceptionRecord;
       PCONTEXT           ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;


ExceptionRecord describes the exception that was raised and caused the invocation of our handler. It contains the following data:


typedef struct _EXCEPTION_RECORD
{
   DWORD                     ExceptionCode;
   DWORD                     ExceptionFlags;
   struct _EXCEPTION_RECORD* ExceptionRecord;
   PVOID                     ExceptionAddress;
   DWORD                     NumberParameters;
   ULONG_PTR                 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} 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):


struc CONTEXT
{
  ;Field                             Offset
  .ContextFlags     dd ?             ;0x00
  ;Debug registers
  .Dr0              dd ?             ;0x04
  .Dr1              dd ?             ;0x08
  .Dr2              dd ?             ;0x0C

  .Dr3              dd ?             ;0x10

  .Dr6              dd ?             ;0x14

  .Dr7              dd ?             ;0x18
  ;FPU data
  .FloatSave        FLOATING_SAVE_AREA  ;0x1C
  ;Segment registers
  .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
  ;CS register
  .SegCs            dd ?             ;0xBC
  ;EFlags register
  .EFlags           dd ?             ;0xC0
  ;Stack pointer
  .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:


struc FLOATING_SAVE_AREA
{
  ;Field                             Offset
  .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_EXECUTION (0xFFFFFFFF) - this would tell the operating system to pass control back to our program;
  • 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:

   PVOID WINAPI AddVectoredExceptionHandler(
        __in ULONG FirstHandler,
        __in PVECTORED_EXCEPTION_HANDLER VectoredHandler );

or RemoveVectoredExceptionHandler function to remove it:

    ULONG WINAPI 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:

SEH stack

0x0006FAA0      0x0006FAA4      ;pointer to EXCEPTION_POINTERS structure
0x0006FAA4      0x0006FAB0      ;pointer to EXCEPTION_RECORD structure
0x0006FAA8      0x0006FC00      ;pointer to CONTEXT structure

VEH stack

0x0006FAA0      0x0006FAB0      ;pointer to EXCEPTION_RECORD 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!


No comments:

Post a Comment

Note: Only a member of this blog may post a comment.