12.16. Countering Disassembly

Problem

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.

Solution

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.

Discussion

Many disassemblers assume that long runs of NULL bytes are data, although some will continue to disassemble regardless. In the Intel instruction set, 0x00 is the opcode for add al, [eax]—a valid instruction. The following macros use NULL bytes to increment the eax register by pushing eax, loading the address of the pushed value into eax, and executing add al, [eax] instructions as many times as the user specifies.

#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) ...

Get Secure Programming Cookbook for C and C++ now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.