|
Here's a proof of concept.
This will "encrypt" (scramble, rather) the strings at compile time and decrypt at runtime.
#ifndef SCRAMBLEH<br />
#define SCRAMBLEH<br />
<br />
<br />
<br />
<br />
#define STRING_SCRAMBLE(s00, s01, s02, s03, s04, s05, s06, s07, s08, s09, \<br />
s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, \<br />
s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, \<br />
s30, s31) \<br />
{ \<br />
char(s00 ^ 0xa3), \<br />
char(s01 ^ 0x54), \<br />
char(s02 ^ 0xff), \<br />
char(s03 ^ 0x75), \<br />
char(s04 ^ 0xe7), \<br />
char(s05 ^ 0x44), \<br />
char(s06 ^ 0x4b), \<br />
char(s07 ^ 0x23), \<br />
char(s08 ^ 0xbf), \<br />
char(s09 ^ 0x45), \<br />
char(s10 ^ 0x3b), \<br />
char(s11 ^ 0x56), \<br />
char(s12 ^ 0xf8), \<br />
char(s13 ^ 0x98), \<br />
char(s14 ^ 0x5b), \<br />
char(s15 ^ 0xf4), \<br />
char(s16 ^ 0xb5), \<br />
char(s17 ^ 0x87), \<br />
char(s18 ^ 0x7b), \<br />
char(s19 ^ 0x0f), \<br />
char(s20 ^ 0xf4), \<br />
char(s21 ^ 0x76), \<br />
char(s22 ^ 0xb9), \<br />
char(s23 ^ 0x34), \<br />
char(s24 ^ 0xbf), \<br />
char(s25 ^ 0x1e), \<br />
char(s26 ^ 0xe7), \<br />
char(s27 ^ 0x78), \<br />
char(s28 ^ 0x98), \<br />
char(s29 ^ 0xe9), \<br />
char(s30 ^ 0x6f), \<br />
char(s31 ^ 0xb4), \<br />
'\0' \<br />
} <br />
<br />
#define LICENSE_STRING_CHECKSUM(s) \<br />
(s[ 0] << 0) ^ \<br />
(s[ 1] << 8) ^ \<br />
(s[ 2] << 16) ^ \<br />
(s[ 3] << 0) ^ \<br />
(s[ 4] << 8) ^ \<br />
(s[ 5] << 16) ^ \<br />
(s[ 6] << 24) ^ \<br />
(s[ 7] << 8) ^ \<br />
(s[ 8] << 0) ^ \<br />
(s[ 9] << 8) ^ \<br />
(s[10] << 16) ^ \<br />
(s[11] << 24) ^ \<br />
(s[12] << 0) ^ \<br />
(s[13] << 8) ^ \<br />
(s[14] << 16) ^ \<br />
(s[15] << 24) ^ \<br />
(s[16] << 0) ^ \<br />
(s[17] << 8) ^ \<br />
(s[18] << 16) ^ \<br />
(s[19] << 24) ^ \<br />
(s[20] << 0) ^ \<br />
(s[21] << 8) ^ \<br />
(s[22] << 16) ^ \<br />
(s[23] << 24) ^ \<br />
(s[24] << 0) ^ \<br />
(s[25] << 8) ^ \<br />
(s[26] << 16) ^ \<br />
(s[27] << 24) ^ \<br />
(s[28] << 0) ^ \<br />
(s[29] << 8) ^ \<br />
(s[30] << 16) ^ \<br />
(s[31] << 24)<br />
<br />
<br />
extern "C" void __cdecl exit(int);<br />
<br />
inline char* __STRING_UNSCRAMBLE(const char s[], char clear[32], <br />
unsigned compileTimeChksum) <br />
{ <br />
unsigned curChksum = STRING_CHECKSUM(s);<br />
<br />
if (compileTimeChksum != curChksum) <br />
exit(0);<br />
<br />
char temp[] =<br />
STRING_SCRAMBLE(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], <br />
s[10], s[11], s[12], s[13], s[14], s[15], s[16], s[17], s[18], s[19], <br />
s[20], s[21], s[22], s[23], s[24], s[25], s[26], s[27], s[28], s[29],<br />
s[30], s[31]);<br />
<br />
for (unsigned i = 0; i < 32; i++)<br />
clear[i] = temp[i];<br />
<br />
return (char*)clear; <br />
};<br />
<br />
<br />
#define STRING_DECL(NAME) \<br />
extern const char NAME ## _Scrambled[]; \<br />
extern char NAME ## _Clear[32]; \<br />
extern const unsigned NAME ## _CheckSum;<br />
<br />
#define STRING_UNSCRAMBLE(NAME) \<br />
__STRING_UNSCRAMBLE(NAME ## _Scrambled, NAME ## _Clear, NAME ## _CheckSum)<br />
<br />
#define STRING_DEF(NAME, VALUE) \<br />
const char NAME ## _Scrambled[] = STRING_SCRAMBLE VALUE; \<br />
char NAME ## _Clear[32]; \<br />
const unsigned NAME ## _CheckSum = STRING_CHECKSUM(NAME ## _Scrambled);<br />
<br />
<br />
#endif
(Obviously, change the encryption key...)
Downside: hardcoded 32-character length for strings (could perhaps be expanded), and all the downsides CXR has. Benefits: does not require extra build step.
|
|
|
|
|
This could be probably expanded into something more general using the for example the template capabilities of the C++ preprocessor. And I hear even the C preprocessor is Turing complete...
So, who makes the most elegant solution?
Bonus point for arbitrary length strings (not hard-coded to 32 chars), unicode support,
public key encryption (no secret key in the binary), compression...
|
|
|
|
|
Chris:
First of all thanks for sharing your code.
When I try to crypt the string "\\LocalMachine\\SOFTWARE\\Classes\\CLSID\\{8F99C758-2F07-495d-8533-D1F2C4522108}\\" it just doesn't work.
I took out the final \\ and presto!
Is this a bug or a feature?
Sheers
Martin Jimenez
|
|
|
|
|
mjimenez wrote:
Is this a bug or a feature?
bug
easy enough to fix, though.
in CTokenizer::GetToken, in the switch statement in the middle, make the following change:
switch (*(pInput + i + 1))
{
case _T('"'):
out+= _T("\\\"");
i++;
continue;
break;
default:
--->
---> out+=c;
--->
---> out+=*(pInput + i + 1);
--->
---> i++;
continue;
break;
}
Image Toolkits | Image Processing | Cleek
|
|
|
|
|
I see now that the strings contain characters above 0x7F. To be safe, I'd suggest generating \x escapes, instead of putting the characters directly in the CPP file. For example instead of "|||" , generate "\x8a\x8f\x86" .
--Mike--
Just released - 1ClickPicGrabber - Grab & organize pictures from your favorite web pages, with 1 click!
My really out-of-date homepage
Sonork-100.19012 Acid_Helm
|
|
|
|
|
Michael Dunn wrote:
To be safe
how does that make it any more safe?
-c
No matter how fast light travels it finds the darkness has always got there first, and is waiting for it.
-- Terry Pratchett,
|
|
|
|
|
I can recall one time that I had a Chinese font name in a string literal, and it compiled fine on a Chinese language system, but generated a compiler error on an English system. When the name was encoded with \x sequences, it compiled fine.
In general, all characters over 0x7F are better being encoded with \x since the meanings of the characters 0x80-0xFF change depending on the ANSI code page in use. Using \x removes the possibility of a breakage.
--Mike--
Just released - 1ClickPicGrabber - Grab & organize pictures from your favorite web pages, with 1 click!
My really out-of-date homepage
Sonork-100.19012 Acid_Helm
|
|
|
|
|
makes sense.
the latest source package (as soon as CP updates it, that is) will output \x-style characters. it will also fix some parsing issues.
thanks for the tip.
-c
No matter how fast light travels it finds the darkness has always got there first, and is waiting for it.
-- Terry Pratchett,
|
|
|
|
|
Well, OK, maybe my situation wasn't that grave, but I did need to obfuscate some strings for a project at work and I had no clue how to do it so the code was maintainable. CXR works perfectly!
--Mike--
Just released - RightClick-Encrypt v1.3 - Adds fast & easy file encryption to Explorer
My really out-of-date homepage
Sonork-100.19012 Acid_Helm
|
|
|
|
|
always glad to help.
-c
Conservative:
One who admires radicals centuries after they're dead.
-- Leo C. Rosten
|
|
|
|
|
Building unicode strings is easy. I only program in English. Here are the few guielines.
Treat the chars as unsigned short.
when converting to hex the format should be like this
in Ansi 'A' = 0x41 "\x41"
IN Unicode 'A' = 0x0041. "\x0041"
srana
|
|
|
|
|
yes. but making CXR Unicode-enabled is much more complicated than that.
-c
Conservative:
One who admires radicals centuries after they're dead.
-- Leo C. Rosten
|
|
|
|
|
Did you forget to add a .CXR file to the test application? The resutling strings.cpp file is there but the source file is not. So the test app doesn't compile as is.
Todd Smith
|
|
|
|
|
it's called strings.cx. this is one of the things i'm waiting to upload.
-c
Conservative:
One who admires radicals centuries after they're dead.
-- Leo C. Rosten
|
|
|
|
|
For this part
#include <algorithm>
const char * __pCXRPassword = "SexyBeast";
class CCXR
{
protected:
Why not include all of that code in a CXR.inc file and then do the following
const char* __pCXRPassword = "SexyBeast";
#include "CXR.inc"
Then you don't have to embed all of that code in CXR. You could also change your implementation later on fairly easy. Just point to a different CXR.inc file.
It also seems like the encoder/decoder could be broken out into it's own set of reusable classes.
P.S. Regardless of what others think I like the idea of encrypting text in your exes
Todd Smith
|
|
|
|
|
Todd Smith wrote:
Then you don't have to embed all of that code in CXR.
that would make it cleaner, but it would introduce the possibility of CXR.EXE and the decoder being out of sync. the way it is now, if CXR changes the way it encodes (which it will do as soon as i upload), nothing breaks, since CXR.Exe will just spit out the new decoder along with the newly-encoded strings. there's no version issues to worry about.
if you want to use the encoder/decoder, just pluck them out of the CXR project. it's all there.
-c
Conservative:
One who admires radicals centuries after they're dead.
-- Leo C. Rosten
|
|
|
|
|
Try this instead of ASSERT(0);
ASSERT( !"Illegal string length in Decrypt" );
Todd Smith
|
|
|
|
|
yeah, that's the sexy way to do it, i guess.
i have a couple of nice changes to upload, but the site won't let me. i'll add your ASSERT while i'm waiting.
-c
Conservative:
One who admires radicals centuries after they're dead.
-- Leo C. Rosten
|
|
|
|
|
DOH, I had seen this before and didn't make the connection.
*SLAP* myself for being stupid.
Tim Smith
"Programmers are always surrounded by complexity; we can not avoid it... If our basic tool, the language in which we design and code our programs, is also complicated, the language itself becomes part of the problem rather that part of the solution."
Hoare - 1980 ACM Turing Award Lecture
|
|
|
|
|
I just read about it in Game Programming Gems. There's a lot more goodies in there besides that one.
Todd Smith
|
|
|
|
|
do the unicode version
go on go on
puleeeaaassseeeeeee
|
|
|
|
|
there are certain, umm, difficulties. but, i'm trying.
-c
Conservative:
One who admires radicals centuries after they're dead.
-- Leo C. Rosten
|
|
|
|
|
This is a great idea, but why use a readable string, although obfuscated, as password or seed for an encryption routine?
I often take some bytes from somewhere in an executable and use that as a password. This makes it very hard to recognize it as a string or even a password.
VictorV
|
|
|
|
|
Good point, but it still has its uses. I put hundreds of strings in my code for error message purposes. They are so comprehensive that they are useful aid to any cracker in reverse engineering my code. This is a neat way of obfusticating them. Thanks Chris!
Gary
|
|
|
|
|
Over the years I've learned that many authors use methods such as this one in the belief that it actually stops or delay crackers a great deal (a 'cracker' is someone who removes copy protections). The reason they believe this is probably because they have no or little experience and knowledge about reverse engineering, and the tools of the trade such as disassemblers and system level debuggers. It's by all means understandable, but it doesn't make it any less wrong.
The fact is that it doesn't result in any serious delay for a cracker. And no, I'm not only thinking of "professional crackers" as some manufacturers of commercial software protections often put in somewhere as a saving clause (they do of course know their protections will be in broken in no time, but they never tell you, or fail to realize, that it's most likely done by a college student than by someone getting paid to do it).
The cracker can easily create a script or a plug-in in a tool like Datarescue's Interactive Disassembler, which for instance will put the decrypted string as a comment to the encrypted data by the press of a key. After all, the decryption routine, including any required keys, is right there in the code, in front of the cracker; don't you believe for a second that it's hard to find and/or extract such routines, because it isn't. Or he can just as easily observer the decrypted string in memory using a debugger.
What's important here is to understand that it's a waste of time (and money) to spend hours, days and sometimes even weeks, on creating copy protections such as the one presented in the article. The only impact it will have is on the product's price, which will increase at the customer's expense. What if the time and effort instead had been used to add more useful features, to increase the code's stability and performance, or to improve marketing and so forth? I know I'm not the only one who strongly believes that this is what attracts customers and ultimately leads to increased success. Time has already proven that copy protections never worked; don't waste your efforts there.
|
|
|
|
|