this book. This is accomplished by modifying the program’s layout,
logic, data, and organization in a way that keeps it functionally identical
yet far less readable. There are many different approaches to obfusca-
tion, and this chapter discusses and demonstrates the most interesting
and effective ones.
Embedding Antidebugger Code Another common antireversing
approach is aimed specifically at hindering live analysis, in which a
reverser steps through the program to determine details regarding how
it’s internally implemented. The idea is to have the program intention-
ally perform operations that would somehow damage or disable a
debugger, if one is attached. Some of these approaches involve simply
detecting that a debugger is present and terminating the program if it is,
while others involve more sophisticated means of interfering with
debuggers in case one is present. There are numerous antidebugger
approaches, and many of them are platform-specific or even debugger-
specific. In this chapter, I will be discussing the most interesting and
effective ones, and will try to focus on the more generic techniques.
Eliminating Symbolic Information
There’s not really a whole lot to the process of information elimination. It is
generally a nonissue in conventional compiler-based languages such as C and
C++ because symbolic information is not usually included in release builds
anyway—no special attention is required. If you’re a developer and you’re
concerned about reversers, I’d recommend that you test your program for the
presence of any useful symbolic information before it goes out the door.
One area where even compiler-based programs can contain a little bit of
symbolic information is the import and export tables. If a program has numer-
ous DLLs, and those DLLs export a large number of functions, the names of all
of those exported functions could be somewhat helpful to reversers. Again, if
you are a developer and are seriously concerned about people reversing your
program, it might be worthwhile to export all functions by ordinals rather
than by names. You’d be surprised how helpful these names can be in revers-
ing a program, especially with C++ names that usually contain a full-blown
class name and member name.
The issue of symbolic information is different with most bytecode-based
languages. That’s because these languages often use names for internal cross-
referencing instead of addresses, so all internal names are preserved when a
program is compiled. This creates a situation in which many bytecode pro-
grams can be decompiled back into an extremely readable source-code-like
form. These strings cannot just be eliminated—they must be replaced with
Antireversing Techniques 329