Uninformed: Informative Information for the Uninformed

Vol 4» 2006.Jun

Handling Unhandled Exceptions

When an exception goes through the initial phase of the exception dispatching process and is not handled by any of the registered exception handlers for the thread that the exception occurred in, the exception dispatcher must take one final stab at getting it handled before forcing the application to terminate. One of the options the exception dispatcher has at this point is to pass the exception to a debugger, assuming one is attached. Otherwise, it has no choice but to try to handle the exception internally and abort the application if that fails. To allow this to happen, applications can make a call to the unhandled exception filter associated with the process as described in [5]. In the general case, calling the unhandled exception filter will result in kernel32!UnhandledExceptionFilter being called with information about the exception being dispatched.

The job of kernel32!UnhandledExceptionFilter is two fold. First, if a debugger is not present, it must make a call to the top-level UEF registered with the process. The top-level UEF can then attempt to handle the exception, possibly recovering and allowing execution to continue, such as by returning EXCEPTION_CONTINUE_EXECUTION. Failing that, it can either forcefully terminate the process, typically by returning EXCEPTION_EXECUTE_HANDLER or allow the normal error reporting dialog to be displayed by returning EXCEPTION_CONTINUE_SEARCH. If a debugger is present, the unhandled exception filter will attempt to pass the exception on to the debugger in order to give it a chance to handle the exception. When this occurs, the top-level UEF is not called. This is important to remember as the paper goes on, as it can be a source of trouble if one forgets this fact.

When operating with no debugger present, kernel32!UnhandledExceptionFilter will attempt to decode the function pointer associated with the top-level UEF by calling kernel32!RtlDecodePointer on the global variable that contains the top-level UEF, kernel32!kernel32!BasepCurrentTopLevelFilter, as shown below:

7c862cc1 ff35ac33887c push dword ptr [kernel32!BasepCurrentTopLevelFilter]
7c862cc7 e8e1d6faff   call kernel32!RtlDecodePointer (7c8103ad)

If the value returned from kernel32!RtlDecodePointer is not NULL, then a call is made to the now-decoded top-level UEF function, passing the exception information on:

7c862ccc 3bc7         cmp     eax,edi
7c862cce 7415         jz kernel32!UnhandledExceptionFilter+0x15b (7c862ce5)
7c862cd0 53           push    ebx
7c862cd1 ffd0         call    eax

The return value of the filter will control whether or not the application continues execution, terminates, or reports an error and terminates.