Monday, March 23, 2015

Simple source code level tricks that will make reverse engineering harder

Many people rely only on virtualization software when protecting their binaries which is often very bad. There's plenty of information on existing VM protections on popular reversing sites, some even offer what is pretty much a 1-click devirtualization tool.

However, whether there's existing tools for fighting your choice of VM or it's still undocumented, there's absolutely no reason why you shouldn't put in extra effort to make reverse engineering harder. I will demonstrate one very simple method to do so: emulation of binary operations on the source code level.

Here's a simple implementation of binary addition for 32 bit numbers:
... and here's a header file with some other operations implemented: obf_tricks.h

After emulating the simple operations, you can implement some more complex operations based on the simple ones. For example, three simple ways to compare two integers using XOR, XNOR and bit counting:
#define X_ISEQUAL1(x,y)    (X_XnorIntegers(x,y) == -1)
#define X_ISEQUAL2(x,y)    (X_CountHighBits(X_XnorIntegers(x,y)) == 32)
#define X_ISEQUAL3(x,y)    (X_XorIntegers(x,y) == 0)

For a quick demonstration here's an extremely simple C code that will print all command line arguments:
... which translates into a very straightforward code: main_disassembly_normal.txt

Now we can rewrite the main application using these macros:
... which now translates into something not that straightforward: main_disassembly_obf.txt

This is a very primitive obfuscation attempt and every somewhat experienced reverser will have no real issues understanding the code. However, if you combine this with virtualization software you will complicate things further and the reverser will have to invest more time into the process of understanding how your algorithms work.

Please note that this is just a simple PoC for demonstration. In real world you should come up with your own ideas.. and it's really not hard to come up with something that does not look like the usual code modern compilers output. Start with obfuscation of some very simple operations and then you can base more complex ones on them.

No comments: