views:

311

answers:

9

If I have an integer like this in several places in my code...

int my_secret = 42;

... is it possible to make it more difficult to find that integer in the compiled program? I've seen this done with strings, for example by shifting each letter by x characters and then un-shifting them at runtime, but I doubt this technique would work well with numbers.

+11  A: 

This never works. Secret keys should never, ever be in code. Creating them at runtime works. Obfuscation is surely tempting providence.

dirkgently
+1. I agree. Plus, a determined reverse engineer will work it out anyway.
Ninefingers
"Creating them at runtime works."Could you please clarify? I realize that obfuscation is a bad long-term solution, but I just need this to slow down the cracking process a bit.
igul222
While I agree that obfuscation almost by definition doesn't make it impossible to discover something about the original code, but only makes the process more difficult... perhaps the OP doesn't require a 100% secure solution and obfuscation will be sufficient. Deriving the value for `my_secret` through some computation might do in this case.
stakx
@igul222: What I mean is: Generate the string/value at runtime using some algorithm that has fairly random elements. Look up on how to create initialization vectors for example.
dirkgently
@stakx: If this production code, he needs to be aware. If it's not, even better -- he will not make this error. Obfuscation doesn't make the process difficult, encryption does.
dirkgently
You can make it very hard to find an integer by assembly level obfuscation if you want, yes 0.001% of the programming population will be able to crack it .... but I'm sure the guy doesn't require this level of protection for a multi-million dollar development project.
Hassan Syed
@Hassan Syed: ... or binary fuzzing.
dirkgently
@ dirkgently: Agreed. Take note that I wrote "more difficult", not "difficult". :)
stakx
As I said in a answer below I think the answer is to do nothing. There isn't a simple way for someone to find the 42 like there is with a string. It's already obfuscated unless you disassemble the and understand the program.
Kevin Gale
+2  A: 

You can do this by splitting this value between two variables. For instance like this:

volatile int my_secret_1 = 20;
volatile int my_secret_2 = 22;

and then use my_secret_1 + my_secret_2 instead of my_secret.

The volatile keyword is needed because most of (if not all) the c compilers would optimize it otherwise. In any way it is better to see what assembler code is produced by a compiler.

Max
so...volatile int secret_1 = 13;volatile int secret_2 = 29;int my_secret = secret_1+secret_2;... right?
igul222
That's correct. You can do int my_secret = secret_1+secret_2; or you can just define a macro for my_secret, so it is substituted with secret_1+secret_2.
Max
+3  A: 

You could calculate it at runtime via some function the compiler can't optimize such using the square of the number and then taking the square root via a math library function.

Of course the problem is that none of this type of stuff will stop a determined person.

It could also be argued that you really don't need to bother. Obfuscating a string makes a lot of sense because there are tons of easy to use tools that will dump strings from an exe. Your 42 however will just be encoded as a binary number. The whole exe is just a long sequence of binary numbers and there isn't a simple tool to search for the 42. You would have to disassemble the exe and understand the assembly. Anyone who is going to go through that much trouble is likely to figure out the number no matter what you do.

So the short answer is don't bother it's obfuscated enough for casual use.

Kevin Gale
+2  A: 

The initial question in Hassan's comment is the critical one. It depends on what you're keeping secret, and why, as to how much work is -worth it-. Generally speaking, hiding something from someone who is using the program which (at some point) puts those values together is impossible to do forever. You can make it harder for an attacker, however.

The question then becomes how much work you want to go to in order to make it harder for that attacker. You can then do anything from code obfuscation (not very secure, but may deter a very casual attacker and is relatively easy to do, especially since the original source can be commented with what's going on) to full on encryption and some of the "black box" type methods that have been used for copy protection (though even those are ultimately breakable) to, if this is critical enough, providing this as something to the effect of a web service where the code is not going to the end user. Even that isn't always failsafe.

So, how secret do you want your secret, and how much work are you willing to put into trying to keep it that way?

Todd
A: 

There really is no way to hide just an integer in the program, as someone could just step through a debugger to determine its final value.

Your best bet is to use some auto-obfuscator to obfuscate the whole routine/program.

BlueRaja - Danny Pflughoeft
+1  A: 

How to use the ones complement

int secret = ~42;
printf("%0X %0x" , secret , ~secret );

prints

FFFFFFD5 42

EDIT: Or using a macro

#define OBFUSCATE(X) (~(X)^0xdeadbeef)

int secret = OBFUSCATE( 42 );
printf("%0X %d" , secret ,OBFUSCATE( secret ));

2152413A 42
stacker
Now all you need to do is find a way to hide `0xdeadbeef` from prying eyes
Hasturkun
+1 for life, etc. I guess 0xcafebabe has the same problem. :-)
trashgod
and it will be 42 in the compiled binary thanks to the optimizer ;)
Bartosz Wójcik
+2  A: 

There is no way to completely hide such secrets from determined attackers, but there are ways to raise the bar (which might sometimes serve as both a deterrent, and a temporary measure.)

The simplest way for doing this is by applying one-time-pads like XOR.

int pad = 322;
int secret = 360;
int value = pad ^ secret; // This is 42

You can add combinations of such one-time-pads, along with obfuscated cryptographic functions to make it harder for an attacker to find the value.

Note that although this makes it harder for attackers to derive the key by looking at the compiled code, they can still attach a debugger to a running process and pull the computed key right out of memory. In fact, there are debuggers (such as IDA pro) that make stuff like this almost trivial.

You also have to worry about the OS paging your key to disk after it has been computed, which can be extracted quite trivially. (Using something like mlock() to lock pages to memory can help you with this.)

Anyhow, this is a very tricky problem, one that many software authors are battling with to implement unintrusive (e.g., no validating keys over the network) licensing schemes.

0xfe
This will not work, because the compiler will optimize out 360 ^ 322 and replace it with 42. So the application could be cracked by searching for the value 42 in the binary. And this is the thing igul222 tries to avoid.
Max
@Max That's correct (I didn't intend to leave the literals there). That said, my primary point remains that you can run the key over a number of cryptographic transformations (the simplest of which is XOR) to increase obfuscation.
0xfe
+1  A: 

Hide representing its value in another number base. See example at base conversion and base 64

lsalamon
+2  A: 

I've heard of people using self-modifying code for obfuscation purposes. As others have said, someone determined enough can still crack it, but it makes life tougher on a would-be attacker if they can't even see the final code disassembled or set breakpoints in it. (Setting a breakpoint amounts to replacing a byte of memory with an INT 3 instruction; if that memory gets modified as part of a self-modifying code operation, the breakpoint will disappear, possibly corrupting the instructions there and leading to even more fun.)

It's still possible to single-step through the code in a debugger. To partially counteract that, you can test IsDebuggerPresent() occasionally and lead the attacker on a wild goose chase if so. Of course this too can be counter-counteracted, e.g. by DLL shimming or even creating a low-level device driver if necessary.

j_random_hacker
This is overly complicated and would require a lot of work. BTW you can set a hardware breakpoint which does not change any bytes in the program. Or even something that OllyDbg calls Memory Breakpoint which is a trick of emulating a breakpoint by changing memory page access rights.Anyway I think that the poster wanted a very basic thing.
Max
I agree it's probably overkill, thought I'd mention it for completeness because a few answers say it's easy to undo obfuscations via disassembly. The idea is to make the attacker do much more work than you do. Good point about hardware debug registers BTW.
j_random_hacker