Code obfuscation
Solidshield can protect functions with several techniques to cover the spectrum of "security performance VS execution performance" trade-off.
The availability of such modes depends on the protected target and on the size of the function.
A summary of all modes, listed in descending order of security and performance demand:
Obfuscation Technique | Best use-case | Code expansion ratio |
---|---|---|
Virtualization | Functions invoked rarely containing sensitive code or handling confidential data. E.g.: initialization functions, code handling keys, platform integrity or licensing functions | 1 : 10.000 - 200.000 |
Emulation | Non-real-time functions, invoked frequently. | 1 : 50 - 300 |
Just-in-Time assembly | Sensitive functions containing loops iterating multiple thousands times. | 1 : 1 + Assembly overhead |
Lazy assembly | Sensitive functions that are invoked inside a loop iterating multiple thousands times. | 1 : 1 + One-time assembly overhead |
Load-Time assembly | Functions that does not allow any run-time overhead. | 1 : 1 |
Control Flow Shadowing | Functions with few branches. | 1 : 1 + 10 - 100 per basic block |
Virtualization
At protection time, the protection server generates a Virtual Machine with unique architecture and syntax, the protected code is translated into bytecode tightly coupled to the virtual machine.
The virtual machine is a set of interpreters, or executors, embedded into the protected binary. Every bytecode line can be decoded and interpreted only by its corresponding executor.
Integrity checks, targeting the bytecode, the virtual machine and the rest of the binary, are uniformly triggered during the sequential interpretation of the bytecode.
Code virtualization maximizes the variability of the code expansion enhancing proportionally the efforts for reverse engineering task.
For this reason, virtualization requires precision in its implementation: it is better to avoid CPU intensive loops to avoid impacting performances significantly.
Emulation
Original code is translated and expanded into a platform-abstracted representation. Original code is translated and expanded into a platform-abstracted representation (Intermediate Representation) then compiled for the target architecture. Code emulation delivers a first half of virtualization (platform-abstracted representation) without requiring run-time bytecode interpretation. So it delivers a good compromise of obfuscation and code integrity for the majority of heavy duty code.
Just-in-Time assembly
At each invocation of protected function, the Virtual Machine will assemble the code in memory, execute it and then erase it.
Lazy assembly
At the first execution of a protected function, the Virtual Machine will assemble the code in memory and execute it. Subsequent calls to the function will land directly on the code in memory. The scenario where lazy is preferable compared to Just-in-Time is when the function is invoked from a loop iterating multiple thousands times: by making it lazy the assembly time is not multiplied by the number of loops.
Load-time assembly
At launch of the program, the Virtual Machine will assemble the code in memory and link future calls to the code in memory.
Control Flow Shadowing
The Control Flow Shadowing (CFS) is a technique designed to enhance the security of a binary program's control flow graph. It involves the strategic modification of this graph, which may include replacing branching instructions or inserting additional security-related instructions. These changes incorporate calls to specialized functions that perform integrity checks and other security measures. By integrating these checks directly into the program's flow, the Control Flow Shadowing effectively obfuscates the control flow. This increased complexity makes it more challenging for attackers to manipulate, analyze, or bypass the program's security mechanisms.