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.XOR
ing 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
Well, this code decrypts a string but how about encrypting ?
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());
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:Download
Git users: scroll down to the repository link Latest release: April 24, 2013, size: 1140 bytes, 41 linesCRC32:
20d1119b
MD5:
30a1d8720414f0eb138342fe10ccf4cb
SHA1:
a25720834dc752faf3d985860fcefce750a09f43
SHA256:
1995da4d81265001c3cf2b88f11d6d623cb25b74d178955bb6e60b7d737052c8
Stay up-to-date:git clone https://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-randompassword
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;
}