Thursday 26 December 2013

[Reverse] Simple code deoptimization

In this post I would like to write about code deoptimization strategies and where it may be needed.

First of all there is quite a little use of deoptimization and that is why I haven't found anything about it in the Internet. Usually developer should write the fastest running code that is possible. Therefore if he/she writes very inefficient code that will cause program to delay on simple functions and that developer will be fired or noone will accept such performance.

There are couple of use-cases (probably more, you may leave a comment with addition) when deoptimization can be helpful:
  • Reverse engineering CTF tasks
  • Slow behavior emulation
In first category the goal is to force contestants to patch or understand inefficient things in calculations. Second may be useful for debugging or testing.

The goal of the deoptimization is to slow down speed of execution of the program. Let's split deoptimization  on manual, when developer intentionally write inefficient code, and automatic, when other software is used to decelerate binary. Obfuscators may sometimes do such deoptimizations when code is dynamically evaluated using eval() function or something like that. Further discussion of automatic means is out of this post scope.

How can developer significally decrease "speed" of application?
The main idea is to use less efficient algorithm to do the same work. For example, using simple array sorting algorithms like bubble sort or so on instead of O(N log N) ones.

But what if you have only 10 elements to sort. All algorithms will finish this work in a trice on modern computers. Let's assume that any function or algorithm consists of multiple basic operations. In case of sorting it may be pair swapping. In order to slow down your algorithm and to increase execution time you may need to either of
  • increase time of basic operation which includes little or no time between basic operations. 
  • significally increase amount of basic operations.
To increase interoperation time you can use :
  • Timers, sleep() to create a delay
  • Any I/O operations
  • Synchronization primitives
To increase amount of operations:
  • Use less efficient algorithm (probably with specific knowledge of execution flow)
  • Insert dummy operations
Calls like sleep(), any console output printing functions and dummy synchronization are easy to track and patch which makes them less efficient in use for reverse CTF tasks, however these function are very easy to use and predictable to emulate delayed behavior. In order to delay execution for CTF tasks second way is preferable to make task more difficult.

Let's illustrate manual deoptimization process and try to slow down addition operation. Which can be written as :
result = a + b;
Let's use less efficient algorithm which increments result needed amount of times:
result = a;
while (b != 0) { result++; b--;}
We may know that C integer type is used (32 bits) and therefore we may use decrement operation instead of increment:
int result = a;
unsigned int end = -1;
unsigned int count = end - b + 1;
while (count != 0) { result--; count--;}
If this is not inefficient enough you may do additional k * 2 ** 32 increment or decrement operations.

No comments:

Post a Comment