Uninformed: Informative Information for the Uninformed

Vol 4» 2006.Jun


Setting the Top-Level UEF

In order to make it possible for applications to handle all exceptions on a process-wide basis, the exception dispatcher exposes an interface for registering an unhandled exception filter. The purpose of the unhandled exception filter is entirely application specific. It can be used to log extra information about an unhandled exception, perform some advanced error recovery, handle language-specific exceptions, or any sort of other task that may need to be taken when an exception occurs that is not handled. To specify a function that should be used as the top-level unhandled exception filter for the process, a call must be made to kernel32!SetUnhandledExceptionFilter which is prototyped as[6]:

LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(
  LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);

When called, this function will take the function pointer passed in as the lpTopLevelExceptionFilter argument and encode it using kernel32!RtlEncodePointer. The result of the encoding will be stored in the global variable kernel32!BasepCurrentTopLevelFilter, thus superseding any previously established top-level filter. The previous value stored within this global variable is decoded using kernel32!RtlDecodePointer and returned to the caller. Again, the encoding and decoding of this function pointer is intended to prevent attackers from being able to use an arbitrary memory overwrite to redirect it as has been done pre-XPSP2.

There are two reasons that kernel32!SetUnhandledExceptionFilter returns a pointer to the original top-level UEF. First, it makes it possible to restore the original top-level UEF at some point in the future. Second, it makes it possible to create an implicit ``chain'' of UEFs. In this design, each UEF can make a call down to the previously registered top-level UEF by doing something like the pseudo code below:

... app specific handling ...

if (!IsBadCodePtr(PreviousTopLevelUEF))
    return PreviousTopLevelUEF(ExceptionInfo);
else
    return EXCEPTION_CONTINUE_SEARCH;

When a block of code that has registered a top-level UEF wishes to deregister itself, it does so by setting the top-level UEF to the value that was returned from its call to kernel32!SetUnhandledExceptionFilter. The reason it does it this way is because there is no true list of unhandled exception filters that is maintained. This method of deregistering has one very important property that will serve as the crux of this document. Since deregistration happens in this fashion, the register and deregister operations associated with a top-level UEF must occur in symmetric order. An example of this is illustrated in figure [*], where top-level UEFs Fx and Gx are registered and deregistered in symmetric order.

Figure: Symmetric register and deregister of UEFs
Image symdiag

In the diagram in figure [*], the top-level UEF Fx is registered, returning Nx as the previous top-level UEF. Following that, Gx is registered, returning Fx as the previous value. After some period of time, Gx is deregistered by setting Fx as the top-level UEF, thus returning the top-level UEF to the value it contained before Gx was registered. Finally, Fx deregisters by setting Nx as the top-level UEF.