• Tidak ada hasil yang ditemukan

Structured Exception Handling

Dalam dokumen The Hacker's Guide to Reverse Engineering (Halaman 135-139)

An exception is a special condition in a program that makes it immediately jump to a special function called an exception handler. The exception handler then decides how to deal with the exception and can either correct the problem and make the program continue from the same code position or resume exe- cution from another position. An exception handler can also decide to termi- nate the program if the exception cannot be resolved.

There are two basic types of exceptions: hardware exceptions and software exceptions. Hardware exceptions are exceptions generated by the processor, for example when a program accesses an invalid memory page (a page fault) or when a division by zero occurs. A software exception is generated when a pro- gram explicitly generates an exception in order to report an error. In C++ for example, an exception can be raised using the throw keyword, which is a commonly used technique for propagating error conditions (as an alternative to returning error codes in function return values). In Windows, the throw keyword is implemented using the RaiseExceptionWin32 API, which goes down into the kernel and follows a similar code path as a hardware exception, eventually returning to user mode to notify the program of the exception.

Structured exception handling means that the operating system provides mechanisms for “distributing” exceptions to applications in an organized manner. Each thread is assigned an exception-handler list, which is a list of rou- tines that can deal with exceptions when they occur. When an exception occurs, the operating system calls each of the registered handlers and the han- dlers can decide whether they would like to handle the exception or whether the system should keep on looking.

Windows Fundamentals 105

07_574817 ch03.qxd 3/16/05 8:35 PM Page 105

The exception handler list is stored in the thread information block (TIB) data structure, which is available from user mode and contains the following fields:

_NT_TIB:

+0x000 ExceptionList : 0x0012fecc +0x004 StackBase : 0x00130000 +0x008 StackLimit : 0x0012e000 +0x00c SubSystemTib : (null) +0x010 FiberData : 0x00001e00 +0x010 Version : 0x1e00 +0x014 ArbitraryUserPointer : (null) +0x018 Self : 0x7ffde000

The TIB is stored in a regular private-allocation user-mode memory. We already know that a single process can have multiple threads, but all threads see the same memory; they all share the same address space. This means that each process can have multiple TIB data structures. How does a thread find its own TIB in runtime? On IA-32 processors, Windows uses the FS segment reg- ister as a pointer to the currently active thread-specific data structures. The current thread’s TIB is always available at FS:[0].

The ExceptionListmember is the one of interest; it is the head of the cur- rent thread’s exception handler list. When an exception is generated, the proces- sor calls the registered handler from the IDT. Let’s take a page-fault exception as an example. When an invalid memory address is accessed (an invalid memory address is one that doesn’t have a valid page-table entry), the processor gener- ates a page-fault interrupt (interrupt #14), and invokes the interrupt handler from entry 14 at the IDT. In Windows, this entry usually points to the KiTrap0E function in the Windows kernel. KiTrap0Edecides which type of page fault has occurred and dispatches it properly. For user-mode page faults that aren’t resolved by the memory manager (such as faults caused by an application accessing an invalid memory address), Windows calls into a user-mode excep- tion dispatcher routine called KiUserExceptionDispatcherin NTDLL.DLL. KiUserExceptionDispatchercalls into RtlDispatchException, which is responsible for going through the linked list at ExceptionListand looking for an exception handler that can deal with the exception. The linked list is essentially a chain of _EXCEPTION_REGISTRATION_RECORDdata structures, which are defined as follows:

_EXCEPTION_REGISTRATION_RECORD:

+0x000 Next : Ptr32 _EXCEPTION_REGISTRATION_RECORD +0x004 Handler : Ptr32

106 Chapter 3

A bare-bones exception handler set up sequence looks something like this:

00411F8A push ExceptionHandler

00411F8F mov eax,dword ptr fs:[00000000h]

00411F95 push eax

00411F96 mov dword ptr fs:[0],esp

This sequence simply adds an _EXCEPTION_REGISTRATION_RECORD entry into the current thread’s exception handler list. The items are stored on the stack.

In real-life you will rarely run into simple exception handler setup sequences such as the one just shown. That’s because compilers typically aug- ment the operating system’s mechanism in order to provide support for nested exception-handling blocks and for multiple blocks within the same function.

In the Microsoft compilers, this is done by routing exception to the _except_handler3 exception handler, which then calls the correct excep- tion filter and exception handler based on the current function’s layout. To implement this functionality, the compiler manages additional data structures that manage the hierarchy of exception handlers within a single function. The following is a typical Microsoft C/C++ compiler SEH installation sequence:

00411F83 push 0FFFFFFFFh 00411F85 push 425090h

00411F8A push offset @ILT+420(__except_handler3) (4111A9h) 00411F8F mov eax,dword ptr fs:[00000000h]

00411F95 push eax

00411F96 mov dword ptr fs:[0],esp

As you can see, the compiler has extended the _EXCEPTION_REGISTRA- TION_RECORD data structure and has added two new members. These mem- bers will be used by _except_handler3to determine which handler should be called.

Beyond the frame-based exception handlers, recent versions of the operating system also support a vector of exception handlers, which is a linear list of han- dlers that are called for every exception, regardless which code generated it.

Vectored exception handlers are installed using the Win32 API AddVectored ExceptionHandler.

Conclusion

This concludes our (extremely brief) journey through the architecture and internals of the Windows operating system. This chapter provides the very basics that every reverser must know about the operating system he or she is using.

Windows Fundamentals 107

07_574817 ch03.qxd 3/16/05 8:35 PM Page 107

The bottom line is that knowledge of operating systems can be useful to reversers at many different levels. First of all, understanding the system’s exe- cutable file format is crucial, because executable headers often pack quite a few hints regarding programs and their architectures. Additionally, having a basic understanding of how the system communicates with the outside world is helpful for effectively observing and monitoring applications using the vari- ous system monitoring tools. Finally, understanding the basic APIs offered by the operating system can be helpful in deciphering programs. Imagine an application making a sequence of system API calls. The application is essen- tially talking to the operating system, and the API is the language; if you understand the basics of the API in question, you can tune in to that conversa- tion and find out what the application is saying. . . .

108 Chapter 3

FURTHER READING

If you’d like to proceed to develop a better understanding of operating systems, check out Operating System, Design and Implementationby Andrew S.

Tanenbaum and Albert S. Woodhull [Tanenbaum2] Andrew S. Tanenbaum, Albert S. Woodhull, Operating Systems: Design and Implementation, Second Edition, Prentice Hall, 1997 for a generic study of operating systems concepts.

For highly detailed information on the architecture of NT-based Windows operating systems, see Microsoft Windows Internals, Fourth Edition: Microsoft Windows Server 2003, Windows XP, and Windows 2000by Mark E. Russinovich and David A. Solomon [Russinovich]. That book is undoubtedly theauthoritative guide on the Windows architecture and internals.

109 Reversing is impossible without the right tools. There are hundreds of differ- ent software tools available out there that can be used for reversing, some free- ware and others costing thousands of dollars. Understanding the differences between these tools and choosing the right ones is critical.

There are no all-in-one reversing tools available (at least not at the time of writing). This means that you need to create your own little toolkit that will include every type of tool that you might possibly need. This chapter describes the different types of tools that are available and makes recommendations for the best products in each category. Some of these products are provided free- of-charge by their developers, while others are quite expensive.

We will be looking at a variety of different types of tools, starting with basic

Dalam dokumen The Hacker's Guide to Reverse Engineering (Halaman 135-139)