I Presentation.

I.1 Strings encryption

I’ve found out a lot of people want to be able to encrypt strings in a C or C++ software. There are a lot of methods available, some of them not very user friendly. I present here my own proof of concept code for encrypting string and have them decrypted at runtime.

I.2 The requirements

We want the process to be user friendly, which means:

We are able to tell which string is going to be encrypted and which is not

All strings must be stored in clear-text in the source code (not in encrypted unreadable form).

Encryption/Decryption password is randomly generated for each build without manual intervention

We want the process to be easy:

A single MACRO function is used to mark the secured strings and to decrypt them at runtime.

Encryption is done on the binary code, not on the source code.

Memory must be protected against strings listing:

Strings must be kept encrypted in memory

Limited number of decrypted string at the same time

II The method.

II.1 Mark Strings

In our case we want to be sure we encrypt only strings, and we also want to choose which strings are going to be encrypted. For that we will mark the strings in a way they are recognized after compilation.
The way I choose to mark a string is to append a ’.’ and a NULL character at the end of the string. It is pretty easy to do with a MACRO and during encryption phase cryptor can find the pattern.

In both case printf(%s), strlen, strcmp and other string manipulation functions will stop at the first ’\0’. That means when you need it, the string is decrypted then you can manipulate it like a regular ACSII char *.

II.2 Encryption phase

We want the encryption to be done on the binary code. For that we have to build a cryptor application which is able to recognized the strings which must be secured on the binary executable. This means we are going to have two steps generation. First, the application executable is generated without encryption, next the encryption is done by the cryptor software.

So the first thing is, how are we going to recognize our strings in the binary code?
First, it is important to know there is no way to give an exact and precise list of string from a binary code. There are tools like Strings from Sysinternal which can display a list of strings. It basically returns all series of 3 or more string characters found in string followed 00 character (NULL) which ends all strings in C/C++. The problem with Strings tool is it will return a lot of strings which are in fact just code instruction happening to match the pattern.

We are going to be sure we can find all the strings to secured without false positives by applying two filters:

First we use a method similar to the one used by strings listing programs.

Second we scan the results of operation one for marked strings (characters ’\0’, ’.’, ’\0’ ending the string).

II.3 Decryption phase

Decryption is done one string at a time at runtime. When a char * which is encrypted must be used, it is automatically decrypted and stored in temporary buffer. This is easy to do with a MACRO surrounding declared strings.

In the method described here, only one string at the time is in clear text in the program. This is more secured but leads to limitations in the application source code (see section V for more about that).

Note : Protecting the decryption password is not really the subject here but for more security the access to password and decryption algorithm could be obfuscated or protected by anti-debug/anti-disassembly trick.

III Implementation.

III.1 Encrypted string target application

First we build a XOR string decryption function. Strings are decrypted one at a time and stored in global variable buffer.

/* secStrKey is string decryption password, its value will be replaced at encryption phase by random password generated by cryptor */

IV Going further.

One limitation in the above code is it does not support multi-threading (one decryption store shared by all the threads). There are several possibilities regarding that issue.
Personally I use a dedicated thread storage for strings which must be encrypted by a given thread (one storage per thread). This means the number of decrypted string at runtime is equal to the number of threads.

The current method also brings some limitation in the usage of source code, for example in the same thread, it is not possible to call a function with two parameters being encrypted strings. If you don’t want to worry about that, you can increase the number of strings which can be decrypted at the same time. You could also decide it is OK for you to have all strings decrypted at runtime, in this case you don’t need string storage.

Another possibility for the C++ users is to modify the decryptStr function to make it manipulate String C++ objects. With that method you don’t need explicit string storage as memory management is done dynamically behind the scene.

Source code string encryption is another process. In your link the encryption must be written in the source file which is very heavy to maintain in my opinion. That is why I describe how to encrypt strings directly by patching the binary. What is interresting is the unicode feature that is missing in my poc. I must not be very difficult to adapt my code to unicode of wide char strings.