The exception handling is one of the common features of the Operating System together with programming language runtime. It is very closely related to software security. The programming language like C/C++ together with OS capability can guard a piece of code against the software exceptions by adding a handling construct or exception handler. It is commonly observed that programmers use the exception handler to start execution at another location however a specific type of exception can be handled with a specific exception handler. This is one of the most widely used mechanisms in the software industry and part of almost all programming languages. This is why it is of utmost importance for security researchers, developers and IT administrators to have in-depth knowledge of this mechanism.
This post introduces the concept and highlights a few important questions on the internal working of the Structured Exception Handling (SEH) for better understanding. This is the first post of an upcoming long series of posts where we will dissect the internals of Exception Handling. Every post in this series will include some reverse-engineering of the sample program and its explanation to understand the internal structure and flow. It is expected that the reader has some knowledge of C and WinDbg or any other related debugging tool.
What is an Exception?
An exception is an event that occurs during the execution of a program that requires the execution of code outside the normal flow of control. These exceptions can be either software-generated exceptions of hardware faults.
Hardware Exception – Initiated by CPU e.g. Divide by zero
Software Exception – initiated by software e.g. Code to check parameters can throw an exception when it finds it invalid. Thread can raise an exception by calling RaiseException API.
You can read more textual description on exception handling here. To begin with, we will focus on Structured Exception Handling (SEH) and will continue to expand on that to cover C++ and C# exception handling later in the series.
Structured Exception Handling (SEH) is compiler-specific and most of the compiler do offer SEH support. The SEH is a mechanism to handle both software and hardware exceptions. It gives complete control to the user over the handling of an exception.
Microsoft C/C++ compiler supports:
__try keyword to guard a body of code
__except keyword for an exception handler
__finally keyword for termination handler
//exception handler block
SEH works differently in x86 and x64 platforms. In this post, we consider x86 architecture first because it is easy to read and understand. To keep things simple, let’s just focus on __try, __except combination currently.
Here is the code snippet which has two functions apart from ‘main’. Function ‘SafeDiv’ has the __try, __except block to handle the divide by zero exception. Function ‘Div’ does not have any guarded code.
void Div(int dividend, int divisor, int *pResult);
BOOL SafeDiv(int dividend, int divisor, int *pResult);
DWORD FilterFunction() ;
int result = 0;
printf(“Result = %d\n”, result);
BOOL SafeDiv(int dividend, int divisor, int *pResult)
*pResult = dividend / divisor;
__except( FilterFunction() )
void Div(int dividend, int divisor, int *pResult)
*pResult = dividend / divisor;
When exception (divide by zero in this case) happens in the function ‘SafeDiv’, the code execution changes as follow:
- OS takes control and searches for the exception handler. Also, the exception handler is thread-specific. (How?)
- OS evaluates the filter_expression of all the exception handlers (multiple handlers in case of nested __try, __except) until the exception is handled i.e. filter evaluated to EXCEPTION_EXECUTE_HANDLER, or there are no more handlers. (How?)
- Either OS handles the exception or an exception handler block is executed based on the evaluation of the filter_expression. (How?)
|EXCEPTION_EXECUTE_HANDLER||The system transfers control to the exception handler, and execution continues in the stack frame in which the handler is found.|
|EXCEPTION_CONTINUE_SEARCH||The system continues to search for a handler.|
|EXCEPTION_CONTINUE_EXECUTION||The system stops its search for a handler and returns control to the point at which the exception occurred. If the exception is non-continuable, this results in an EXCEPTION_NONCONTINUABLE_EXCEPTION exception.|
Following is the disassembly (Microsoft C/C++ compiler) of the two functions mentioned in the code above. The highlighted green text in ‘SafeDiv’ is all the code present in ‘Div’ function. You can easily notice that a lot of extra code is added by __try, __except block.
|SafeDiv(With Exception handler)||Div(without exception handler)|
|0:000> uf ex1!safediv
00266a60 55 push ebp
00266a61 8bec mov ebp,esp
00266a63 6afe push 0FFFFFFFEh
00266a65 6850b62b00 push offset Ex1!__rtc_tzz+0x104 (002bb650)
00266a6a 68607f2600 push offset Ex1!_except_handler4 (00267f60)
00266a6f 64a100000000 mov eax,dword ptr fs:[00000000h]
00266a75 50 push eax
00266a76 83c4f4 add esp,0FFFFFFF4h
00266a79 53 push ebx
00266a7a 56 push esi
00266a7b 57 push edi
00266a7c a120c02b00 mov eax,dword ptr [Ex1!__security_cookie (002bc020)]
00266a81 3145f8 xor dword ptr [ebp-8],eax
00266a84 33c5 xor eax,ebp
00266a86 50 push eax
00266a87 8d45f0 lea eax,[ebp-10h]
00266a8a 64a300000000 mov dword ptr fs:[00000000h],eax
00266a90 8965e8 mov dword ptr [ebp-18h],esp
00266a93 c745fc00000000 mov dword ptr [ebp-4],0
00266a9a 8b4508 mov eax,dword ptr [ebp+8]
00266a9d 99 cdq
00266a9e f77d0c idiv eax,dword ptr [ebp+0Ch]
00266aa1 8b4d10 mov ecx,dword ptr [ebp+10h]
00266aa4 8901 mov dword ptr [ecx],eax
00266aa6 c745fcfeffffff mov dword ptr [ebp-4],0FFFFFFFEh
00266aad eb30 jmp Ex1!SafeDiv+0x7f (00266adf)
00266adf b801000000 mov eax,1
00266ae4 8b4df0 mov ecx,dword ptr [ebp-10h]
00266ae7 64890d00000000 mov dword ptr fs:,ecx
00266aee 59 pop ecx
00266aef 5f pop edi
00266af0 5e pop esi
00266af1 5b pop ebx
00266af2 8be5 mov esp,ebp
00266af4 5d pop ebp
00266af5 c3 ret
|0:000> uf ex1!div
00266a40 55 push ebp
00266a41 8bec mov ebp,esp
00266a43 8b4508 mov eax,dword ptr [ebp+8]
00266a46 99 cdq
00266a47 f77d0c idiv eax,dword ptr [ebp+0Ch]
00266a4a 8b4d10 mov ecx,dword ptr [ebp+10h]
00266a4d 8901 mov dword ptr [ecx],eax
00266a4f 5d pop ebp
00266a50 c3 ret
In order to understand the code difference and code flow better, we need to answer the above questions first. In the coming posts of this series, we will work towards these questions.