12.16. Countering Disassembly
An object file disassembler can produce an assembly language version of a binary, which can then be used to understand and possibly modify the binary.
Anti-disassembly tricks are useful in frustrating automatic analysis, but they generally will not hold up to a human review of the disassembly. Make sure to combine the methods presented in the discussion with data or code obfuscation techniques.
Many disassemblers assume that long runs of
bytes are data, although some will
continue to disassemble regardless. In the Intel instruction set,
0x00 is the opcode for
[eax]—a valid instruction. The following macros use
NULL bytes to increment the
register by pushing
eax, loading the address of
the pushed value into
eax, and executing
add al, [eax] instructions as many times as the
#define NULLPAD_START asm volatile ( \ "pushl %eax \n" \ "movl %esp, %eax\n") #define NULLPAD asm volatile ("addb %al, (%eax)\n") #define NULLPAD_END asm volatile ("popl %eax\n") #define NULLPAD_10 NULLPAD_START; \ NULLPAD; NULLPAD; NULLPAD; NULLPAD; NULLPAD; \ NULLPAD_END
This is particularly effective if the value referenced by
eax—that is, the value at the top of the
stack—is used later in the program. Note that many
disassemblers that ignore runs of
NULL bytes allow
the user to override this behavior.
To demonstrate the effect this macro has on disassemblers, the following source code was compiled and disassembled:
void my_func(void) ...