Reversing : The Hacker's Guide to Reverse Engineering

(ff) #1

source files and libraries are all linked into a single executable, many function
boundaries are eliminated through inlining and are simply pasted into the
code that calls them. The machine is eliminating redundant structural details
that are not needed for efficiently running the code. All of these transforma-
tions affect the reversing process and make it somewhat more challenging. I
will be dealing with the process of reconstructing the structure of a program in
the reversing projects throughout this book.
How do software developers break down software into manageable
chunks? The general idea is to view the program as a set of separate black
boxes that are responsible for very specific and (hopefully) accurately defined
tasks. The idea is that someone designs and implements a black box, tests it
and confirms that it works, and then integrates it with other components in the
system. A program can therefore be seen as a large collection of black boxes
that interact with one another. Different programming languages and devel-
opment platforms approach these concepts differently, but the general idea is
almost always the same.
Likewise, when an application is being designed it is usually broken down
into mental black boxes that are each responsible for a chunk of the applica-
tion. For instance, in a word processor you could view the text-editing compo-
nent as one box and the spell checker component as another box. This process
is called encapsulation because each component box encapsulates certain func-
tionality and simply makes it available to whoever needs it, without exposing
unnecessary details about the internal implementation of the component.
Component boxes are frequently developed by different people or even by
different groups, but they still must be able to interact. Boxes vary in size: Some
boxes implement entire application features (like the earlier spell checker
example), while others represent far smaller and more primitive functionality
such as sorting functions and other low-level data management functions.
These smaller boxes are usually made to be generic, meaning that they can be
used anywhere in the program where the specific functionality they provide is
required.
Developing a robust and reliable product rests primarily on two factors: that
each component box is well implemented and reliably performs its duties, and
that each box has a well defined interface for communicating with the outside
world.
In most reversing scenarios, the first step is to determine the component
structure of the application and the exact responsibilities of each component.
From there, one usually picks a component of interest and delves into the
details of its implementation.
The following sections describe the various technical tools available to soft-
ware developers for implementing this type of component-level encapsulation
in the code. We start with large components, such as static and dynamic mod-
ules, and proceed to smaller units such as procedures and objects.


Low-Level Software 27
Free download pdf