Reversing : The Hacker's Guide to Reverse Engineering

(ff) #1
multibyte opcodes. I’m using the __LINE__macro in order to create unique
symbol names in case the macro is used repeatedly in the same function. Each
occurrence of the macro will define symbols with different names. The paste
and pastesymbolsmacros are required because otherwise the compiler just
won’t properly resolve the __LINE__ constant and will use the string
__LINE__instead.
If distributed throughout the code, this macro (and you could very easily
create dozens of similar variations) would make the reversing process slightly
more tedious. The problem is that too many copies of this code would make
the program run significantly slower (especially if the macro is placed inside
key loops in the program that run many times). Overusing this technique
would also make the program significantly larger in terms of both memory
consumption and disk space usage.
It’s important to realize that all of these techniques are limited in their effec-
tiveness. They most certainly won’t deter an experienced and determined
reverser from reversing or cracking your application, but they might compli-
cate the process somewhat. The manual approach for dealing with this kind of
obfuscated code is to tell the disassembler where the code really starts.
Advanced disassemblers such as IDA Pro or even OllyDbg’s built-in disas-
sembler allow users to add disassembly hints, which enable the program to
properly interpret the code.
The biggest problem with these macros is that they are repetitive, which
makes them exceedingly vulnerable to automated tools that just search and
destroy them. A dedicated attacker can usually write a program or script that
would eliminate them in 20 minutes. Additionally, specific disassemblers have
been created that overcome most of these obfuscation techniques (see “Static
Disassembly of Obfuscated Binaries” by Christopher Kruegel, et al. [Kruegel]).
Is it worth it? In some cases it might be, but if you are looking for powerful
antireversing techniques, you should probably stick to the control flow and
data-flow obfuscating transformations discussed next.

Code Obfuscation


You probably noticed that the antireversing techniques described so far are all
platform-specific “tricks” that in my opinion do nothing more than increase the
attacker’s “annoyance factor”. Real code obfuscation involves transforming the
code in such a way that makes it significantly less human-readable, while still
retaining its functionality. These are typically non-platform-specific transfor-
mations that modify the code to hide its original purpose and drown the
reverser in a sea of irrelevant information. The level of complexity added by an
obfuscating transformation is typically called potency, and can be measured
using conventional software complexity metrics such as how many predicates
the program contains and the depth of nesting in a particular code sequence.

344 Chapter 10

Free download pdf