Jump to content


Anti-splashscreen-crack Trick


18 replies to this topic

#1 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

Posted 29 September 2004 - 12:12 AM

Splashscreens can be important for demos and freeware applications, since advertisement is often the only reward the developer gets for them. But splashscreens are very easy targets for crackers. They often don't care about the reason behind 'nag'-screens...

But since we are the developers, we should protect ourselves from them. While it is impossible to create uncrackable code, there are some nice anti-crack tricks. You just have to anticipate on what the cracker will do. The primary tool a cracker uses is a debugger, or similar program which allows to see the application's assembly code in a convenient format. A debugger also automatically translates binary addresses into readable strings, so-called symbols. The trick in this code spotlight attacks exactly those symbols.

Many splashscreens use a Windows dialog. It's easy, just create a dialog resource, copy your picture into it, add some copyright notice, call CreateDialog, and you're done. Crackers know this. They especially know that you're going to call CreateDialog. So even a newbie cracker can place a breakpoint on this function, and wait till it gets called by your application. He doesn't have to understand a lot of assembly code to find exactly where you call CreateDialog. He removes that call, maybe remove a simple timer, and he's done!

Their strength, namely being able to place a breakpoint at CreateDialog, can be turned into a weakness. We can't change the fact that they'll place a breakpoint at the address of CreateDialog, but we do can prevent that breakpoint from being hit! Here's the trick: skip the first instruction(s). Sounds crazy? It isn't. All we have to do is compensate for the skipped instruction. Luckily, for CreateDialog, I'll show you this is easy...

First you have to know that CreateDialog actually is a pointer to another function, called CreateDialogParamA. You can easily see this by (ironically) placing a breakpoint at CreateDialog, and tracing through the assembly code. It doesn't take a lot of assembly knowledge to see that it actually translates into a call to CreateDialogParamA. This is also the function the cracker will really place a breakpoint on. Now, if you trace into this function, you'll find that the first instruction is "mov edi, edi". It should be clear that this instruction does... nothing! And if you look at the binary code, you'll see this instruction takes two bytes. So we can just skip these two bytes and execute our function from there. The newbie cracker will never notice this, since even in our code it won't find the CreateDialogParamA symbol any more.

But how do we do that? Don't panic, there's no self-written assembly code involved here, just some advanced C++. To summarize, what we really want to do is call CreateDialogParamA plus two bytes. Unfortunately you can't just write it in C++ like this:
HWND splash = (CreateDialogParamA + 2)(appInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, (DLGPROC)DefWindowProc, 0);
The C++ compiler doesn't allow you to add offsets to functions, which is of course a good protection. But we can easily fool it, by casting CreateDialogParamA to an integer, adding two, and then converting back to a function pointer of the same type as CreateDialogParamA:
HWND splash = ((HWND (__stdcall *)(HINSTANCE,LPCSTR,HWND,DLGPROC,LPARAM))((int)CreateDialogParamA + 2))
       (dllInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, (DLGPROC)DefWindowProc, 0);
This looks quite complex because I splitted it over two lines, but it's really not that hard. The first line casts to integer, adds two and casts back to the function type. The second line is simply the argument list.

Now keep quite so the crackers don't learn about this trick...

Well, don't get too excited. This trick will only stop the newbie cracker. An experienced cracker will sooner or later figure out what happens. Either way, this simple trick can become a powerful weapon. Every method that fools the tools they use, make it much harder for them to do their 'job'. Assembly code without symbols is almost just as useless as looking at a sequence of zeros and ones.

With many functions you won't be so lucky that it starts with an instruction that does nothing. Most start with "push ebp", one byte long. It modifies the stack so you can't simply call one byte further. But it's not impossible. A "call" instruction only places the return address on the stack, and then performs a "jmp". So let's just do the same thing, using inline assembly:
__asm
{
  push label
  push ebp
  jmp function+1
label:
}
This is a bit more advanced, but applicable to most standard functions. It can also be used to skip bigger parts of functions. And the debugger's call stack will be messed up because it won't detect that the jmp actually replaces a call.

Enjoy!

Nicolas "Nick" Capens

#2 Mihail121

    Senior Member

  • Members
  • PipPipPipPip
  • 1059 posts

Posted 29 September 2004 - 08:15 AM

Nice one, but it's a little crazy don't you think? The implementation of CreateDialogParamA might differ across systems so this might work on, say, WinXP SP1 or something like that.

Anyway, it does the trick! I remember also seeing more tricks like that somewhere. One of them was to use memory leak in one the blit functions to gain access to cool windows stuff :)

#3 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

Posted 29 September 2004 - 09:05 AM

Mihail121 said:

Nice one, but it's a little crazy don't you think? The implementation of CreateDialogParamA might differ across systems so this might work on, say, WinXP SP1 or something like that.
As far as I know, CreateDialogParamA has been there since Windows 95. And it's statically linked so if it works once it will work anywhere.

But you're right, it's not safe to assume that the implementation of dynamically linked functions has remained the same. But that's no problem either. We can simply check whether they start with the byte(s) we try to skip, "push ebp" is simply 0x55. So we can probably make a macro that applies this trick automatically. But note that this can become a weakness. If they spot this code sequence everywhere, they'll very quickly figure out how it works, remove them 'automatically' and continue the ususal cracking work with breakpoints on interesting symbols.

Quote

Anyway, it does the trick! I remember also seeing more tricks like that somewhere. One of them was to use memory leak in one the blit functions to gain access to cool windows stuff :)
Wouldn't that be a crack instead of an anti-crack? :wink:

#4 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 29 September 2004 - 10:21 AM

That is quite an impressive hack. However, what I would be even more impressed with is good statistics about how many sales are actually generated by this sort of thing. In other words, does it actually significantly increase the number of people buying it?

I am all for making people stop cracking your stuff, but this seems a bit extreme. (though not more extreme than some of the stuff I have seen commercially)

I dont mean this to be flame or flamebait, but I wonder if we can come up with solutions such that it wont matter if people crack our software or there won't be a compelling reason to use a crack that someone made.

I use cracks regularly, but this is usually nocd cracks for games that force me to continually swap between my collection of cds each time adding another scratch until the game wont work anymore. I like to keep an image of the play cd on disk or simply perform a full install, and not have to risk ruining yet another disk.

Perhaps this post is just idle wishing, feel free to ignore me, but I cant be the only one who hopes for something better can I?
Jesse Coyle

#5 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

Posted 29 September 2004 - 12:25 PM

NomadRock said:

However, what I would be even more impressed with is good statistics about how many sales are actually generated by this sort of thing. In other words, does it actually significantly increase the number of people buying it?
If they want to crack it, they will. I'm quite sure crackers actually know this kind of trick, and know more ways to circumvent it than we can imagine. Maybe at most it delays them a week. But it's not all about sales. They don't do it to directly lower your sales. They do it for the sport of it. Likewise, I enjoy looking for tricks like this. :cool:

So, if anyone knows other anti-crack tricks like this, please share! More specifically I'm looking for ideas that are easy to implement, yet give the cracker a headache...

#6 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 29 September 2004 - 12:55 PM

Fair enough, sometimes the cat and mouse chase is fun just for the chase.
Jesse Coyle

#7 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

Posted 29 September 2004 - 12:55 PM

I just noticed how devilish this trick can really be made. If you apply it to many calls, it's going to be easy to spot and undo. But, there can be an infinite number of variants. Between the push'es and jmp, you can place dummy code, or even real code that does something else like an important calculation. This will make it harder for the cracker to separate the splashscreen code from the code he shouldn't touch. You can even place (lots of) code between the jmp and label! This is really confusing for the cracker since it will be even harder to figure out where the 'call' happened. He'll look at the call stack and see the return address, not where the jmp was made. And to make him completely loose his mind, you can make the return address point to another function. :wacko:

Use your imagination!

#8 Mihail121

    Senior Member

  • Members
  • PipPipPipPip
  • 1059 posts

Posted 29 September 2004 - 03:48 PM

Right about one thing: if they want to crack it - they will!

#9 SnprBoB86

    Valued Member

  • Members
  • PipPipPip
  • 112 posts

Posted 18 October 2004 - 01:45 AM

The best tricks I have seen are described here (free registration required, but this great site is well worth it)

The short of it is that they had various advanced ASM tricks and one particuarly innovative simple trick. This simple trick operates on the debugging premis that randomly occuring bugs are the hardest to fix. Basically, what they did was implement several different types of exe checksums. The application run different checksums at different times and then if any of these checksums failed they would RANDOMLY break different aspects of the game. For example, a cracked version of the game would result in being unable to pass the 3rd level. Since it took the crackers precious time to get up to the third level and then once they got there they had no concrete way of telling if their crack worked perfectly, they had a difficult time creating a working crack.
Brandon Bloom
http://brandonbloom.name

#10 SpreeTree

    Valued Member

  • Members
  • PipPipPip
  • 265 posts

Posted 18 October 2004 - 06:18 AM

I think that was the route taken by Operation Flashpoint, published by codemasters a few years back. Apparently, the random issues that using a hacked version caused were very hard to pin down, especially, when some of the issues just made it look like you were just plain crap at playing the game.

Bit of a winner idea if you ask me, not sure how hard it is to implement though

Spree

#11 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 18 October 2004 - 06:37 AM

It actually might be a fun way to play a game, if it just gave you a handicap. You could steal the game, and get relatively good at it, and then when you bought the full version, you would be awesome, because you wouldn't have to deal with the handicap.

I learned tennis this way with a very heavy racket with a long neck and very small head.
Jesse Coyle

#12 Ed Mack

    Senior Member

  • Members
  • PipPipPipPip
  • 1239 posts

Posted 18 October 2004 - 10:41 AM

You stole a tennis racket?

#13 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 18 October 2004 - 05:47 PM

Sortof, it was my parent's. Good thing was, that I didn't have to crack it in order to use it, otherwise I would have been in trouble.
Jesse Coyle

#14 SnprBoB86

    Valued Member

  • Members
  • PipPipPip
  • 112 posts

Posted 19 October 2004 - 03:42 AM

lol :-P

well it is probably really easy to implement, but I would definitly make it IMPOSSIBLE to get past a certain point. Maybe just pick one of 10 random ways to die or crash or lose health and do it randomly every so often...

Then ALSO do some other stuff like remove all the powerup items and cut all the ammo by one third and do some other crazy shit. Make it that its so hard htat its impossible because someone who plays a harder version of your game illegally is still playing your game illegally...
Brandon Bloom
http://brandonbloom.name

#15 Kurioes

    New Member

  • Members
  • Pip
  • 2 posts

Posted 06 December 2004 - 03:40 PM

Alternatively, (being the cracker) you can just send a few WM_TIMER messages to the dialog followed by a WM_COMMAND to speed things up.

I tried it using Spy++ on some program with a "countdown button" and it seemed to work. I just hope nobody is smart enough to actually check how long the dialog has been open before closing it :unsure: If you really want to that check can be foiled too (I'm too dumb to do it though).

#16 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

Posted 06 December 2004 - 04:56 PM

Kurioes said:

Alternatively, (being the cracker) you can just send a few WM_TIMER messages to the dialog followed by a WM_COMMAND to speed things up.
Encrypting the time is quite effective, especially when combining multiple timers that should indicate the same period elapsed. :D

#17 Kurioes

    New Member

  • Members
  • Pip
  • 2 posts

Posted 06 December 2004 - 05:39 PM

Nick said:

Kurioes said:

Alternatively, (being the cracker) you can just send a few WM_TIMER messages to the dialog followed by a WM_COMMAND to speed things up.
Encrypting the time is quite effective, especially when combining multiple timers that should indicate the same period elapsed. :D

View Post


Sure it is - fun to code too :unsure:. I think most shareware authors don't bother though.

#18 mstr99

    New Member

  • Members
  • Pip
  • 2 posts

Posted 02 November 2005 - 10:27 AM

SnprBoB86 said:

The application run different checksums at different times and then if any of these checksums failed they would RANDOMLY break different aspects of the game. For example, a cracked version of the game would result in being unable to pass the 3rd level.

There's one problem. If a gamer is using a cracked version, and it starts breaking randomly, he might just think that the game is crap, and delete it. That way you still wouldn't get paid for it. So I therefore believe, that you should let the user know the reason of failure is cracked version. They might already be addicted to the game and thus ready to pay. :sneaky:

Of course you should do these checks with different code blocks when the game advances. Most 0-day crackers don't have time to playtest and find the check which happens just before you defeat the final boss for example.

#19 roel

    Senior Member

  • Members
  • PipPipPipPip
  • 698 posts

Posted 02 November 2005 - 01:40 PM

dude, you replied on a post that is more than one year old!





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users