For purposes of this article we assume that the S/W is built using an embedded Linux system that supports Dynamic Share Object (DSO) modules. The alternative would be to use a static build of the O/S such as Musl which is outside the scope of this article (but we can handle static builds too).
Obfuscation protection cannot "overly increase" the size of the application's RAM and FLASH footprint, nor can it "overly increase" the run-time speed of the application. For a rule of thumb, the footprint cannot be over 20% larger, nor can the speed reduction be over 20%. The software must have the ability to incorporate pragmas that will control, or possibly completely eliminate, obfuscations at selected points in the S/W.
We assume that the S/W is built using the "C" programming language that conforms to MISRA C restrictions.
We will supply rules, described in detail below, for automatically refactoring the "C" source code by utililizing a licensed commercial version of SrcML and Python Beautiful Soup, where:
SrcML converts the "C" source code to an XML-AST format.
Python and Beautiful Soup are used to refactor the XML-AST source code.
SrcML is used again to convert the refactored XML-AST back to "C" source code.
We will refactor each DSO so that they will not formally export any user
functions or data when the DSO's exports are loaded into the calling function's address
space via the dlopen
function! Normally the sole purpose of designing a library is
to access these exports! But knowledge of these exports are critical for the adveserial hacker
who is attempting to reverse engineer the library. Therefore we have developed a hidden channel
mechanism to access a "shrouded" export table when the caller invokes the dlopen
function by using an attribute(constructor)
function defined in the
.init
section of the DSO.
We will refactor the DSO so that all calls to libc
functions are
"shrouded". Run-time tracing of libc
functions is an important reverse engineering
technique that we must block.
The shrouding mechanism, aka "key wrapping", will double the size of the addresses we
wish to protect. The mechanism will be light weight (inline
), and implemented via
registers - in order that there is no single function which the adversary can attack.
Shrouding can also be used to protect constants and strings.
Parameters to protected functions will also be shrouded. This will make it difficult for our adversary to do run-time debugging of the call stack because every function invocation will be different even when the same parameters are used
There will be a separate local variable and global variable shrouding mechanism - each
relying upon its own separate light weight (inline
) library specific
PRNG.
Loops that are order independent can be randomized.
We will supply a pragma mechanism in order to allow the user to fine tune the usage of the above techniques.