Hide Strings In Your Executable

posted by Stephan Brumme

Plain Text

Every constant string in C/C++ programs is easily recoverable in your executables. Microsoft's Process Explorer lists all strings, e.g. Hello World !:



One way to prevent non-programmers from locating your strings is to encrypt them. The most simple method is based on XOR. It's cracked within seconds by serious hackers but can keep away everyone without a programming background. And after all that's 99% of all computer users out there.

XORing your data

The basic idea is as follows: a XOR b XOR b = a, i.e. applying XOR twice give the original value. The variables a and b can be of an arbitrary non-floating-point type. If you want to encrypt strings then char and wchar_t are obvious choices.

Instead of using a constant b, it's a little bit better to have a pass-phrase (another string).
Then you can have a loop and select password[i % passwordLength]. For better performance, passwordLength should be a power of two because then the compiler can replace to slow modulo operation by a much faster AND.

A few lines of C++ is all you need:
hide std::string decode(const std::string& input) { // choose a power of two => then compiler can replace "modulo x" by much faster "and (x-1)" const size_t passwordLength = 16; // at least as long as passwordLength, can be longer, too ... static const char password[passwordLength] = "invalid pointer"; // out = in XOR NOT(password) std::string result = input; for (size_t i = 1; i < input.length(); i++) result[i] ^= ~password[i % passwordLength]; return result; } // "Hello World !" printf(decode("\xde\xf4\xe5\xf2\xfc\xb6\xcc\xb0\xfd\xfc\xf2\xb1\xaa").c_str());
Well, this code decrypts a string but how about encrypting ?
How did I know I have to use \xde\xf4\xe5\xf2\xfc\xb6\xcc\xb0\xfd\xfc\xf2\xb1\xaa ?

The answer is pretty simple: decode works both ways. If you provide it your plain-text string, it will return the encrypted version and if you call it with your encrypted string it will properly decipher it.

My code takes a command-line parameter like this:

HideString "Hello World !"



Note: The quotation marks are required to merge the three parts Hello, World and ! into one single string).

Live Demo

Maybe you are too lazy to launch a console window ... a little bit of Javascript does the trick, too:







Git users: scroll down to the repository link
Download  HideString.cpp
Latest release: April 24, 2013, size: 1140 bytes, 41 lines

CRC32: 20d1119b
MD5: 30a1d8720414f0eb138342fe10ccf4cb
SHA1: a25720834dc752faf3d985860fcefce750a09f43
SHA256:1995da4d81265001c3cf2b88f11d6d623cb25b74d178955bb6e60b7d737052c8

Stay up-to-date:git clone http://create.stephan-brumme.com/hide-strings-executable/.git

If you encounter any bugs/problems or have ideas for improving future versions, please write me an email: create@stephan-brumme.com

Choosing Your Password

I prefer a non-random password that looks like a string emitted by the runtime library: the more obvious, the less obvious. And vice versa ;-)

A problem may occur if letter of your encrypted string is identical to the according letter of your password: if a = b then a XOR a = 0.
Zero terminates any C/C++ string and therefore your string might be cut short. That's the main reason why I included a NOT in my simple encryption scheme because then this collision is rare (but definitely can occur !).

Full Source Code

And that's all:
hide // ////////////////////////////////////////////////////////// // HideString.cpp // Copyright (c) 2011 Stephan Brumme. All rights reserved. // see http://create.stephan-brumme.com/disclaimer.html // #include <string> std::string decode(const std::string& input) { // choose a power of two => then compiler can replace "modulo x" by much faster "and (x-1)" const size_t passwordLength = 16; // at least as long as passwordLength, can be longer, too ... static const char password[passwordLength] = "invalid pointer"; // out = in XOR NOT(password) std::string result = input; for (size_t i = 0; i < input.length(); i++) result[i] ^= ~password[i % passwordLength]; return result; } int main(int argc, char* argv[]) { // "Hello World !" printf(decode("\xde\xf4\xe5\xf2\xfc\xb6\xcc\xb0\xfd\xfc\xf2\xb1\xaa").c_str()); // encrypt command line if (argc == 2) { // apply XOR std::string encrypt = decode(argv[1]); // display encrypted string printf("\ndecode(\""); for (size_t i = 0; i < encrypt.length(); i++) printf("\\x%02x", encrypt[i] & 0xFF); printf("\");"); } return 0; }
homepage