Sign in to follow this  

basic copy proection

This topic is 4301 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a game im getting ready to sell, this is my first attempt to sell a game. I've read up on a number of software protection schemes and they all seem to be crackable. So i've decided i may as well see if i can just do something basic to deter any n00bs. So this is what i've thought of: 1) write my own vector interrupt for int 3 to stop debuggers. i dont know how to do interrupts in windows or if this will even work, if any one has any suggestions/links to articles 2) for online play, send the users key to the server, if the key s valid, the client recives a list of servers. This fails when the user joins by ip. This also fails with LAN and single player. I could force the user to be online to play (ala battlefield 2, and you buy online anyway) but then hackers can just bypass the online check. 3) one idea i had was to send the clients cpuid to a server, the server will then encrypt it and send it back to the client, this will then verify the player when they play offline (ie. you have to be online to install the game only). This should stop random copying of my game, but the hackers could probably just remove the code that checks the key is valid... plus i dont like the idea of cpu locking... any other ideas ? currently im just thinking 1 and 2, but it would be nice to stop simply copy for those people that play offline

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
1) everything can be cracked, the only thing you can hope for is deterring the less determined crackers.
2) the commercial solutions are written by experts. If they cannot make something watertight, don't even try to do it yourself.
3) what to do when a pirated version sends a valid key (not unheard of, key generators are common and a lot of people will give out their keys to friends and friends' friends etc. etc.)?
4) not all machines set a CPUID, or anything else that can uniquely identify them on their own. Other things like MAC addresses can be changed. And what procedures would you have in place to reset valid customers who change their hardware?
4a) what procedures do you have in place for people who aren't connected at all?
5) I doubt you can stop debuggers, there are just too many advanced ways that are (virtually) undetectable. The most determined cracker will have access to kernel debuggers, remote debugging facilities, and will also be able to intercept the data you send to your server for verification and change it on the fly.

Share this post


Link to post
Share on other sites
Anything can be cracked. Its just a matter of time, and the patience of the cracker.

As for antidebugger, Eldad Eilam in his book "Reversing: Secrets of Reverse Engineering" has a couple of good tricks to detect a debugger. This one here was the best, as its good for any debugger (kernel / user mode), and prolly won't raises a false positive.

bool bExceptionHit = false;

__try
{
_asm
{
pushfd
or dword ptr [esp], 0x100 //set the trap flag
popfd

nop
}

}
__except(EXCEPTION_EXECUTE_HANDLER)
{
bExceptionHit = true;
}

if(!bExceptionHit)
printf("A debugger is present");


Pretty much, if a debugger is present, it'll swallow the exception. So if the exception is hit, no debugger. I've yet to try this myself, but the author is brilliant, so I don't see why that souldn't compile.

GL!

Share this post


Link to post
Share on other sites
Quote:
2) the commercial solutions are written by experts.

Bwahaha.. I refer you to the recent Sony/First4Internet debacle. Not only is the entire design of their rootkit/"protection" a security hole, but it also contains pretty stupid bugs. And this in a kernel mode driver..


_Sigma: ooh, a productive tip! Nice :) These type of threads usually end up a silly discussion of whether or not to add copy protection, instead of valuable information on how to do so.
Why don't I chip in too, then:

Ways to detect debugger:
1) IsDebuggerPresent. Trivially dodged by debuggers (need only change flag in PEB)
2) timing. Impossible to avoid - single-stepping or handling lots of debug events will inevitably slow things down (unless remote debugging)
3) detecting *installation* of debugger. This is always an arms race and actually not nice to users because they might need a debugger for other tasks and may not be trying to hack your program.
4) trap flag method mentioned above

Misc. tips on how to annoy reversers:
1) scatter around (slightly different) inlined routines that wipe out all debug regs. This makes placing breakpoints across large regions of code infeasible (at least unreliable).
2) do not make it easy/desirable to spread a single cracked version. In more detail: if it's break-once run-anywhere, your protection isn't that good. Idea: compile a version for each customer that includes their name prominently displayed somewhere.
3) update frequently to invalidate simple patch-byte-here instructions and require reanalysis.
4) read in a recent BlackHat presentation about a way of protecting your memory from external analysis. Awesome!

Further reading: gold mine; also search for "Fravia".

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I come bearing good news! There is nothing you have to do anymore, from a technical standpoint, to protect your games! There is this new thingy, called copyright law, and it enables you to sue anyone who copies your game without permission! Neat huh?

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
I come bearing good news! There is nothing you have to do anymore, from a technical standpoint, to protect your games! There is this new thingy, called copyright law, and it enables you to sue anyone who copies your game without permission! Neat huh?

Wow. That is the most useless suggestion that I've ever had the misfuture to read.

IsDebuggerPresent isn't worth your time :P Unless your code is packed, its so damn easy to pass. You just search the imports for it, then if present, bp on it, once you hit, change the first OP to a 'ret' or 'ret 8' Can't remeber off the top of my head. And bam. Its defeated. See how easy? So put it in there, but don't rely on it.

*BUT* There is a way around this, again described by Elad. Just impliment your own 'IsDebuggerPresnt' code.

//Taken from Elad's book.
mov eax,fs:[0x18] //fixed a small error here
mov eax,[eax+0x30]
cmp byte ptr [eax+0x2], 0
je RunProgram ;jump to the main program code here
;inconspicuously kill the app here.

Now thats way harder to pick out.

As Jan Wassenberg, timing is a really good way to defeat a debugger as well. Just set up another thread that monitors the first thread, and if it detects that the other thread is suspended, it terminates the app. Again, Elad's book is brilliant, so I'd grab a copy of that if you can.

Quote:

_Sigma: ooh, a productive tip! Nice :) These type of threads usually end up a silly discussion of whether or not to add copy protection, instead of valuable information on how to do so.

I know eh? Ah well. I just hope it helped him/her.

I don't recommend looking to see if a debugger is installed, as that will just piss people off. I have a few apps that won't run with SoftIce and what not installed, which is just plain annoying, so I've had to go in a disable that crap myself. Just not worth pissing off your customers.

Hope this helps.

[Edited by - _Sigma on March 4, 2006 9:25:29 PM]

Share this post


Link to post
Share on other sites
Write your app in malbolge and ship a malbolge interpreter with it. There is no way anybody would be crazy enough to even bother cracking it.

Something that is similar to the malbolge way of protection: code morphing

Share this post


Link to post
Share on other sites

A couple more random tips:

* Do a checksum of the exe to detect modification.

* Don't check your key in a single spot. Use different code in both spots. Make the second check later on (in the middle of the game) and do something mean if it fails, such as:

rdtsc
push eax
ret

Have fun tracking that one down ;)

Share this post


Link to post
Share on other sites
The #1 thing to do to make reverse engineering more difficult is to turn on the right optimization and other compiler/linker settings. Which compiler (and language, for that matter) are you using?

Another evil trick would be to use functions for read-only data arrays (implemented using 'naked functions' with the content being solely "__asm __emit #" or equiv) and/or crafting code manually and putting it in data variables.

Share this post


Link to post
Share on other sites
Quote:
Original post by _Sigma

__try
{
_asm
{
pushfd
or dword ptr [esp], 0x100 //set the trap flag
popfd

nop
}

}
__except(EXCEPTION_EXECUTE_HANDLER)
{
bExceptionHit = true;
}

if(!bExceptionHit)
printf("A debugger is present");


I'm not the least bit familiar with assembly. Can someone walk me through this little bit and explain what it does? Very interesting!

Share this post


Link to post
Share on other sites
Quote:
IsDebuggerPresent isn't worth your time :P Unless your code is packed, its so damn easy to pass. You just search the imports for it, then if present, bp on it, once you hit, change the first OP to a 'ret' or 'ret 8' Can't remeber off the top of my head. And bam. Its defeated. See how easy? So put it in there, but don't rely on it.

Constant arms race. Might be a good idea to verify integrity of that API's code - if changed, it's a surefire indicator of messing around.

Quote:
*BUT* There is a way around this, again described by Elad. Just impliment your own 'IsDebuggerPresnt' code.

That is exactly how the API is implemented. Incidentally, there's little benefit as pretty much any access to PEB except for registering __except handler is a red flag and worthy of investigation. Also, and easy way around this is to clear that flag (stored in the PEB as mentioned) at startup.

Quote:
Again, Elad's book is brilliant, so I'd grab a copy of that if you can.

Unfortunately it's not available in Uni library and there's no room in the budget.. too bad.

Quote:
rdtsc
push eax
ret

Have fun tracking that one down ;)

You'd have to wipe out the current stack frame (otherwise cracker gets a backtrace directly to your clever code, which is counterproductive!), but idea is promising.

Quote:
Another evil trick would be to use functions for read-only data arrays (implemented using 'naked functions' with the content being solely "__asm __emit #" or equiv) and/or crafting code manually and putting it in data variables.

Snag: .text is read-only; you'd have to use VirtualProtect (another red flag of cleverness).

Share this post


Link to post
Share on other sites
Quote:
Original post by leiavoia
Quote:
Original post by _Sigma

__try
{
_asm
{
pushfd
or dword ptr [esp], 0x100 //set the trap flag
popfd

nop
}

}
__except(EXCEPTION_EXECUTE_HANDLER)
{
bExceptionHit = true;
}

if(!bExceptionHit)
printf("A debugger is present");


I'm not the least bit familiar with assembly. Can someone walk me through this little bit and explain what it does? Very interesting!

Are you familiar with what the 'stack' is? Its pretty much just the ram that your app has been allocated. It's first-in-last-out.
PUSH blah
pushes blah onto the stack
POP blah
pops blah off the stack.

PUSHFD pushes the entire contents of the EFLAGS register onto the stack. So this is done to preserve the state of the EFLAGS register.

or dword ptr [esp], 0x100
That just sets the trap flag.
" Trap generating instructions generate an exception that transfer control from software (usually application programs) to the operating system."

I'm not 100% on the basics of the trap flag tho, so if someone wants to add to this.

POPFD will just pop the contents of the EFLAGS register back into the registers.

NOP is just "No operation" aka 0x90 in hex.

__except(EXCEPTION_EXECUTE_HANDLER)
{
bExceptionHit = true;
}

this just attempts to trap the exception raised by setting the trap flag. (this is like a try-catch block)

So ya...does that make sense?

Quote:

That is exactly how the API is implemented. Incidentally, there's little benefit as pretty much any access to PEB except for registering __except handler is a red flag and worthy of investigation. Also, and easy way around this is to clear that flag (stored in the PEB as mentioned) at startup.

Yes, but this is much less likely to be spoted. Guaranteed it'll stump someone for a few minutes, and 100% it'll blow the mind of a shitty cracker.

Quote:

rdtsc
push eax
ret

I don't get this...Why is this bad?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Ever hear of NOP? It kills all your futile security attempts.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Try EXECryptor from http://www.strongbit.com. The 2.x serie remains uncrackable since its inception on July 2004. Also they frequently improve it to keep up to date. I think this is the strongest among commercial protection schemes.

Regards
Bill

Share this post


Link to post
Share on other sites
Quote:
Original post by _Sigma
Quote:
Original post by Anonymous Poster
Ever hear of NOP? It kills all your futile security attempts.

Eh? NOP = No Operation.
Any test you put in can be replaced by a number of NOPs that takes the same number of bytes.

Machine-code obfuscation is probably the best bet as far as a one-click type of solution, since it make it very difficult to understand what needs to be removed and what the correct way to do it would be.

Next to that, I think the best option might be to put all the source code into a single file (including those portions of the CRT that are relied upon), because that would help the compiler's optimizer (which in MSVC is much more advanced than the one in the linker, it seems) out and it would make 'function library signature' packages fail to match most of the standard-library functions. If you add in a change of calling convention (such as from "cdecl" to "fastcall"), certain optimizer settings ("Global Optimization" on, "Inline Functions" to highest setting, "Intrisics" to on, "Omit Frame Pointers" to on, all runtime checks disabled, if at all possible RTTI and C++ exceptions disabled), and certain linker settings ("/Fixed:X" where X is 0x80000000 minus the size of the executable in memory, "/GY /OPT:REF,ICF=20 /SAFESEH:NO"). The idea is to have as much information as possible removed from the executable, so that reversers have a much more difficult time figuring out what each function does.

Also, be careful with error messages. You should avoid error messages like "SaveGameChecksum: Unable to verify checksum of save game %s" and should instead go for something like "Invalid or corrupted save game". The reason is that the latter gives away less information about what is being done. If you want to get usefull logs to help debug problems, use error codes instead of names, such as "Error 392: Unable to load save game". That gives away even less information, but could still be usefull to you since you'll have a table of codes to descriptions.
The reason for this is that a good debugger will show which strings are referenced in each function, and seeing an error message prefixed by a function name means the reverse won't have to figure out what the function does because you just labeled it for him/her.

Share this post


Link to post
Share on other sites
The checksum will detect if anyone changes a bit of your code. If they place NOPs in all your fancy debug detecting code, you'll detect that before they even get a chance to execute the NOPs.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by blaze02
The checksum will detect if anyone changes a bit of your code. If they place NOPs in all your fancy debug detecting code, you'll detect that before they even get a chance to execute the NOPs.


Oh wow, let's hope they don't NOP the checksum detection too... :P

Share this post


Link to post
Share on other sites
I wonder if the EXECryptor makes machine code use other machine code as data. For example, it could change one instruction into 5 that do the same thing, then change code in another part that multiplies by a hard-coded constant to instead multiply by the value in a code address that 'just happens'(was modified) to hold the right value.

One thing that bothers me about EXECryptor is that the license (hidden in a tiny icon on the buy page) either not written by a lawyer or does not apply in the US, because US law requires certain parts to be only capital letters and those parts are in normal case in their license. Also, there are spelling and gramar mistakes everywhere (some seem like problems a non-native english speaker would have, but others seem like the kinds of mistakes that native-english-speakers make all the time). It does sound like a good strategy for protecting code, but I don't know if I'd trust their implementation.

[Edited by - Extrarius on March 3, 2006 2:37:25 PM]

Share this post


Link to post
Share on other sites
Caculate the checksum of your exe except for the parts that contain strings of text. Also include a string that will be used to display the registrant's name thanking him for his support. When someone registers the game, encode his name and registration number (separatly), put the encoded strings in the exe (make a small program that will only do this). Calculate the checksum of the registered name and encode the other strings in your exe (and possibly data files) with the checksum (with the same small program).

When the user starts the program he will see the thank you message with his name. If the user finds the name string and tries to modify it, suddenly the text and data files won't be decoded properly (since they are encrypted with the user's name). If the user succeeds in cracking the protection, you will still be able to decode the registration number that is secretly hiding encrypted somewhere in the exe.

You can go a step further by including random strings when encoding your exe to make it harder to find the data that is modified with different exes.

This won't stop piracy but it should help you know who distributed the program if it's massively distributed. Unfortunately if someone registers with false informations, you are toast.

This solution requires a lot of work, probaly more than what you may gain from it. But it could prevent the people who have limited knowledge of computers from copying it.

---------------------------
Visit www.collectionsbp.com

Share this post


Link to post
Share on other sites
Octarinne: All it would take is two executables from different registered people, because they could decrypt the files and find out what is different from them and that would be the registration number. If you encode things using the registration number, they'll just decode them and then remove the registration number. Without something like EXECryptor, it's not really possible to hide anything. Even with such a tool, somebody that's been doing reversing long enough probably has a library of tools that can handle the task.

Share this post


Link to post
Share on other sites

This topic is 4301 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this