Reversing : The Hacker's Guide to Reverse Engineering

(ff) #1
Executable Data Sections

Another area in program memory that is frequently used for storing applica-
tion data is the executable data section. In high-level languages, this area typi-
cally contains either global variables or preinitialized data. Preinitialized data
is any kind of constant, hard-coded information included with the program.
Some preinitialized data is embedded right into the code (such as constant
integer values, and so on), but when there is too much data, the compiler
stores it inside a special area in the program executable and generates code
that references it by address. An excellent example of preinitialized data is any
kind of hard-coded string inside a program. The following is an example of
this kind of string.


char szWelcome = “This string will be stored in the executable’s
preinitialized data section”;

This definition, written in C, will cause the compiler to store the string in the
executable’s preinitialized data section, regardless of where in the code szWelcome
is declared. Even if szWelcomeis a local variable declared inside a function, the
string will still be stored in the preinitialized data section. To access this string,
the compiler will emit a hard-coded address that points to the string. This is
easily identified while reversing a program, because hard-coded memory
addresses are rarely used for anything other than pointing to the executable’s
data section.
The other common case in which data is stored inside an executable’s data
section is when the program defines a global variable. Global variables provide
long-term storage (their value is retained throughout the life of the program)
that is accessible from anywhere in the program, hence the term global. In most
languages, a global variable is defined by simply declaring it outside of the
scope of any function. As with preinitialized data, the compiler must use hard-
coded memory addresses in order to access global variables, which is why
they are easily recognized when reversing a program.


Control Flow


Control flow is one of those areas where the source-code representation really
makes the code look user-friendly. Of course, most processors and low-level
languages just don’t know the meaning of the words if or while. Looking at
the low-level implementation of a simple control flow statement is often con-
fusing, because the control flow constructs used in the low-level realm are
quite primitive. The challenge is in converting these primitive constructs back
into user-friendly high-level concepts.


Low-Level Software 43
Free download pdf