In this article, I will describe how to obfuscate strings using C++ constexpr. Source codes used here can be found on my GitHub account, wrapped in a pretty header file. Before jumping straight into the code, however, I need to explain what we want to achieve here. Usually, when compiling a program, strings are inserted into the binary in raw format. If one opens the final binary executable in Notepad or any hexeditor, the strings are clearly visible. Strings can also be extracted using lots of tools such as “strings” in Linux.
For many reasons, you might not like strings to be exposed that easy. String obfuscation is something you would consider if you designed a CTF challenge, or when you wanted to make it harder for crackers to crack your software. Strings obfuscation won’t make your software bulletproof but is an essential step towards having stronger binary protections.
To have obfuscated strings in the final binary, we need to encrypt strings at compile time. Unfortunately, most of the programming languages are not very rich when it comes to compile-time function execution. Usually, all you have is just a simple engine that enables you to write Macros, which are not sufficient for writing string obfuscation methods. Therefore, you have to do it manually with a pre-compilation script that goes through all your source files and replaces all the strings it finds with encrypted versions, or, a post-compilation script that does the same thing on the output binary. Either way, it will be an ugly solution, that imposes an additional step in your build process. It might not be very reliable or painful when debugging or unit testing.
C++ constexpr allows us to mark a function or expression for the compiler, saying that the result of the computation can be calculated at compile time, provided parameters with known constant values. Below, shows an example of computing the factorial of 4 at compile time.
Having constant strings and using constexpr, we can store an string in an encrypted format, computed at compile time. The code below shows how to encrypt strings with simple xor encryption method using constexpr.
In the above code, “obfuscator” is a class with a member array that stores data in an encrypted form. Defining obfuscator’s constructor as constexpr ensures that this member array is encrypted at compile time. Although any symmetric encryption algorithm can be used, we employ the simplest one here, XOR encryption. Compiling the above code:
gcc --std=c++14 -O0 -S -masm=intel constexpr2.cc
And examining the generated assembly, indeed we see that the string “Hello” is stored in the encrypted form:
Note that the Ascii code for ‘H’ is 72, and when xored with 85 (0x55), the result will be 29, which shows that “Hello” is stored in an encrypted format.
Now, to use the encrypted strings, we need to have them decrypted first. For that purpose, we create a decryption method for the “obfuscator” class. Such method would be like:
Compiling above code
gcc --std=c++14 -fno-stack-protector -O0 -S -masm=intel constexpr3.cc
And looking at the generated assembly code again, we see that this time, “Hello” is stored as a stack string which indeed is even better for binary protection. Not only “Hello” is stored in an encrypted format, but it also has bytecodes in between each character which makes it harder to recover by any auto analysis tool.
Now, the final problem is that, writting strings like
obfuscator<6>("Hello");
is such a pain, but C++ Macros to the rescue. A simple macro can be used to pack everything into a single line with the employment of a lambda function:
Using above macro and packing everything in a header file, we can simply encrypt our strings in a C++ application.
The final header file can be found on GitHub.
Conclution
C++ constexpr makes it much more convenient to obfuscate strings at compile time. Using this feature, you wont need any additional step in your build process. Everything is wrapped up in your source code which also makes it much more beautiful when looking at. Aside from being more readable, your code will be also much easier to modify, test and debug.
The downside of using constexpr for obfuscation of strings is a little overhead which is negligible most of the time. Also note that constexpr is only supported on C++14 or above. Unfortunately, C does not support constexprs either.
Hello,
very clever, but I don’t understand the use of the macro STR.
It obfuscates and de-obfuscates the string in the same macro.
In my understanding, we must have 2 macros, one to scramble the text and one for descramble !!!