7

I am looking for a way to obfuscate (in the object code) a test - something like what might be done to check that a license key is valid. What I am trying to prevent is someone searching through an image binary for the code that processes the response.

bool checkError = foo();
if ( checkError ) // I'd like to avoid making a simple check like this one.
{
   // process response
}

This is a simplistic example, but not a recommended approach:

int check = 71 * 13;
check += 35 * isValid(); // will only return 0 or 1

//later (delayed execution of response)
if ( check % 71 )
{
   //process response
}

EDIT: Just to clarify, the actual test is already finished and I'm getting a pass/fail return. My response processing will be a basic jmp and would be interested in pointers on how to obfuscate the location of the jmp.

Dubron
  • 8,661
  • 2
  • 15
  • 10
  • You should know, of course, that this is not a trivial problem. Large software companies like Microsoft spend millions trying to prevent people from bypassing their protection, and yet people still manage to circumvent their efforts. – Charles Salvia Dec 11 '09 at 20:21
  • @Charles Salvia: This is true. I'm not looking for a protection degree from just this question. ;) However, this is my first time attempting something along these lines and I have to admit that I don't know where to begin. – Dubron Dec 11 '09 at 20:25
  • 1
    Macrovision even bought InstallShield to throw their weight behind copy-protecting software. It has not really stopped anything though. Hardware dongles have become pretty rare since they didn’t do much either (everything *always* comes down to software eventually, at which point it becomes hackable). SlySoft regularly blacklists leaked keys, but others keep releasing new ones with every release. I find obfuscation to be best for fun (like the contests) rather than for actual copy-protection. – Synetech Dec 11 '09 at 20:33

4 Answers4

6

One approach would be to put the code that does the license check into a separate DLL. In the main application, load the DLL at runtime and calculate the checksum of the DLL itself. The app stores the checksum that was calculated with the DLL was built. If the checksums don't match, you have several options, show a wrong-version message - a bit obvious; Do not call the license check - less obvious but will be noticed when the attacker wonders why the license check doesn't get called; call a function with a similar name to the real license-check function.

Think of it as using Public Key Encryption. Use a public key as part of the config and have a private key built into the app. If they mess with the public key, the digital signature of the app will be compromised in a detectable way.

I agree with @camccann that it would help to understand the kind of attack you expect. As a last resort, split the license-check into as many parts as is feasible to make it harder to bypass by changing a single branch point.

[EDIT]

Another thought would be to use a State Machine. See the command structure example in the top answer to this question. Put the evaluation of the license check into the form of a hash lookup and a set of dummy function calls into an array along with the proper one. The decision code that evaluates the license check into a table/hash lookup for the appropriate function will not look like your typical

if(){ pass;} else { fail; } 

construct.

Two benefits,
1) there isn't a boolean condition to bypass and
2) they can't do a simple JMP instruction without knowing the address/name of the function to pass control to.

SO thread on a state machine turorial.
SO thread on state machine implementations

Community
  • 1
  • 1
Kelly S. French
  • 12,198
  • 10
  • 63
  • 93
  • 4
    Unfortunately, I feel this misses the area the OP was concerned about. He isn't so much worried about the actual process of checking the license. Instead, he's getting a boolean that represents a pass/fail, and needs to operate specific code based on that condition. However, this boils down to a very simple jmp in the assembly, and a simple hex editor can subvert the conditional check rather trivially if they know where it is. He wants to obfuscate the location of this jmp (if statement), not the actual license check itself. – KevenK Dec 11 '09 at 21:05
  • @Kelly French: Thank you, kindly! This is along the lines of what I was looking for. :) – Dubron Dec 11 '09 at 21:40
  • I like the idea of using state machine techniques. – Michael Burr Dec 12 '09 at 07:27
5

Obfuscation doesn't prevent, merely discourage. A sufficiently skilled and determined attacker will always be able to circumvent whatever obfuscation you use, so what you need to know first is: What kind of people are you trying to thwart here?

C. A. McCann
  • 76,893
  • 19
  • 209
  • 302
  • Thank you for making that distinction. I should have said "discourage" in my question. The people I'm trying to thwart are probably novice attackers as more experienced ones will most likely find a way to get around some of the trickiest methods. – Dubron Dec 11 '09 at 20:23
3

The Secure Programming Cookbook (O'Reilly) has a whole chapter on Anti-Tampering (the actual book has the chapter, not sure what's available on the website). Neat stuff.

acraig5075
  • 10,588
  • 3
  • 31
  • 50
Dan
  • 5,929
  • 6
  • 42
  • 52
3

You could cause a crash by sprinkling the check all over like:

T* data = (T*) new char[sizeof(T) * (check() ? 1 : 0)]
array[i + 1 * (check() ? 0 : 42)].doStuff();

There's a nice article at Gamasutra about crack protection in Spyro that does similar things, then goes further by making the game not crash, just work worse and worse. (You never hit enemies, you walk slower, certain critical objects disappear randomly etc etc.)

Fun read for all programmers, and perhaps useful to you.

Macke
  • 24,812
  • 7
  • 82
  • 118