Programming Techniques:Self Defense in Game Development
Self Defense in Game Development
When programming a game, one has to think of the game's audience. Most of any given game's audience are perfectly content acquiring and playing the game as it was intended. Most of them, even if given the desire, would not use flaws in the game's design to their advantage because they are incapable of exploiting any flaws. But some, though, possess the skills and make a hobby of doing this. So why do we programmers need to worry about this? Most of us would discourage cheating in these ways and those developing large, commercial games could end up losing money if one of these people, called "Crackers" finds a way to bypass the game's anti-distribution measures and makes these "Cracked" versions available to the public for free.
It should be noted that this tutorial has not been in any way reviewed by professional security experts.
Before learning anti-cracking techniques, it is necessary to know your enemy and have an idea of how crackers generally go about their work. When you compile your source code for your game, it is transformed into extremely simple instructions that the actual processor can understand, sometimes called "Machine Code". (For interpreted languages, it is a bit different, but this tutorial will focus on compiled programs.) What a cracker does is find out what goes on inside your game by a process called Reverse Engineering, which is done by one of a few techniques. One consists of looking at the output of a decompiler that basically reverses what your compiler does, with several limitations. The decompiler usually produces assembler level code which is quite difficult to read and has no descriptive variable or function names. However, decompilers such as IDA Pro produce very detailed analysis of the target program and its logic. In this way, the cracker can usually find out the flow of a our program and figure out how to exploit it. Another way some crackers work is by stopping the execution of the machine code in memory using a specially designed debugger like SoftICE. This enables them to view and edit the actual machine code as it is executed.
Crackers use these methods to find critical points in a game, like the point where a game decides whether it is a legal copy or whether the security code given is valid and use one of the methods mentioned to either delete or alter that code in such a way that will achieve their goals.
The original author confused decompilers with disassemblers and didn't fully distinguish between Machine Code and Assembly Code. A decompiler interprets Machine Code into whatever the target high level language is. A disassembler converts Machine Code to Assembly Code. Machine Code is composed of binary digits (represented usually in hex) while Assembly Language consists of mnemonics for commands represented by those binary digits. IDA is a disassembler not a decompiler. An example of a decompiler would be Anakrino, which is used for all .NET languages.
There are several ways in which crackers cheat on games, depending on how exactly they want to cheat and on what kind of a game. With some games, it is as simple as determining the structure of a game's save files, sometimes by reverse engineering and sometimes by simple trial and error and logic. But in multi-player games where the save file is on a server, other techniques must be used. In these games, it is necessary to directly change the value in question in memory. Sometimes this is done with debuggers like SoftICE that let you run an application and control its memory. In other cases, the cracker can just reverse engineer the game itself to make it do what they want or use an external program to inject values into the process.
Aimbots, x-ray vision, and invulnerability - these are external programs with attach themselves to your game and give the player an unfair advantage. You commonly find this in FPSs. This usually involves the program intercepting the packets that are transmitted to the player's machine, modifying the data and transmitting it to the player's game and the other players.
There are fundamentally two kinds of cheats: ones that alter the memory of the game and ones that hook the game or use existing components to achieve some sort of advantage. The way a memory hack works is to use a program, one such program is known as TSearch, to search the games memory for data such as your player’s health. You can then set a breakpoint on the memory address you found that corresponds to your players health in a debugger, such as SoftICE, to see what code accesses that location in memory. Once you have done this it is usually a simple process to stop the game from say, lowering your health value anymore thus achieving god mode. Memory hacks may not be as useful in multi-player games because important values such as your health, ammo, and player coordinates can be kept track of (or verified) by the server; this means that client side and editing them in any way is not going to help you any because even if your end of the game, the client, is telling you that you have 100 health, you probably don't (according to the server). Regardless of that there are usually plenty of other memory hacks you can get away with in multi-player such as radar hacks that allow you to see both your team and the enemy on a minimap if one exists. In multi-player the other kinds of cheats come into play more often.
The general key to preventing crackers from messing with your code is knowing where and how they will do their work, and using that knowledge to come up with preventions. Key areas include:
- Authenticity Key validation routines
- Any other authenticity checks
- Password validation routines
Then make all of these key areas and routines cracker-proof.
- Obfuscate things! Make tons of dummy procedures all called something extremely confusing and put them all over in your code. Make some call another and some dead end and all contain a huge mass of math that looks like what the cracker is looking for, but only one be the real one. Make one procedure call another, and that one call another, and then another, and then the real procedure. Any cracker trying to find his way around that is either very good and very determined, or insane.
- Never distribute debug builds, they contain function name information which give the attacker a foothold in your code. Having a visible label on a function like CheckCDInDrive() is like handing the cracker the program on a plate.
- Use an exe packer like UPX, this prevents the casual cracker from de-compiling your code. It also prevents simple tweaks to the exe from changing the logic of jump instructions. But don't trust a simple exe packer to secure your code. There are unpackers available on the internet for most popular packers. Also, the cracker can use a process patcher to make the logic changes to the program in memory after the exe has decompressed itself.
- Make your key validation algorithm, even if extremely simple, look absolutely huge by adding all sorts of math onto it that all evens out when it is all solved.
- Make any key or password checking routine sleep for a few seconds or even restart the program before continuing. Doing so will make brute force random key/password checks basically impossible.
- In multiple places in your code, check to see whether key routines exist anymore.
- Do not embed any key strings like "Key validation failed" into your EXE. Either encrypt them or dynamically assemble them. Crackers look for strings like that in the raw machine code.
- Try to hide the code of your key validation routines in your game logic. Example: Merge the validation routines with initialization code for graphics, so your program will stop working, if a cracker just removes the routine call.
- If possible, allow the cracker to think they have broken your program, only to stop at a later point (after 1 week or a few levels for example). With any luck, the player will have enjoyed playing the 'extended demo' and go and buy a legitimate copy of the game. The Monkey Island series employed this tactic to great effect.
- Check for the presence of debuggers like SoftICE and TDW in your initalisation code. If they are present, try to crash them or refuse to run.
And also keep a few general points in mind while writing your game.
- Don't take anything for granted. Just because it doesn't seem likely that a cracker will set his system clock to a certain time to take advantage of a random number generator being seeded with the time doesn't mean he won't do it. Alway treat the user as an attacker, validate all input.
- If the program needs to be extremely secure, you could go as far as creating an MD5 sum or such of your entire EXE and check it against a dynamically assembled/encrypted sum through a series of insanely obfuscated routines like mentioned in the first example in the above section.
- Try combining several of these techniques.
- In demo versions of games, be sure to remove all code involved in any features that have been removed as an incentive for the user to buy the full version. Don't just remove the call to the feature removed in a demo version. Crackers will just put back the call if you leave the code in.
As I saw them:
1. It doesn't matter what you name your routines because to a cracker they are just numbers anyway. It doesn't matter how many dummy routines you have if you are not clever about it. They should do real but non-meaningful work on real data and actually be used otherwise it is going to be cake to distinguish between a fake one and a real one. For the most part I don't care if you have a routine that does random math, if it doesn't call anything else I will just step out of it and go about my business. Basically what I am saying is that it is easy for a cracker to see what code is useful to him and what isn't, make it all look useful.
2. I am going to caution against using debugger checks alone because I know someone is going to do it. Remember: if it is done in code it can just as easily be undone.(False, VB Code can only be decompiled to the extent of P-Code, Others will have full decompile services)
3. Use multi-pronged security methods no matter what. You should be doing some checksums no matter what or you can't expect your program to be secure at all. Layer your protections and use many of them otherwise they might as well not even be there because they will be circumvented quickly no matter how secure you think your cd key routines are.
4. Debugger detection, packers, obfuscation, etc. are all cheap OLD tricks-of-the-trade. Using these as a mean of protection is just a waste of time for you. The cracker will bypass them no matter what, usually in a lot less time (and effort) than you spent implementing them.
5. Security through obscurity does NOT work! Seriously. Avoid it as your ultimate security method (although it can make life harder for crackers if done in a meaningful way.)
6. Crackers do NOT erase routines, so checking for their existence does NEVER bring any security (And of course your checking routine will be a routine too, crackable aswell.)
7. The best way to keep a your game cracker-safe is to make it multiplayer and implement security checks server-side. Just never assume the client-side data is right, and give them as little information as possible. Multiplayer games are fun, great for your customers, and awful for crackers.
Cheating is usually not a problem for small-scale single-player games. But for multi-player games or games that allow people to submit high scores, this can be an issue. Preventative measures are usually specific to one particular game, so you will have to think for yourself how cheaters will attack. Some ideas:
- Do what you can to stealth and obfuscate any protocols used to report scores or communicate with a server. Use special keys that have complicated or obfuscated generation routines that the cracker will have difficulty reading.
- Don't trust the score as reported, trust it only when other game variables seem to be in sync with the score reported.
In revision of the first bullet: encrypt your packets! Even a lot of experienced game hackers won't touch encrypted packets even if they are capable of reverse engineering enough information to decrypt them because it can be so time consuming; this is especially true since you can do enough cheating using other methods to have a nice edge without having to decrypt anything in most games. Have the server encrypt packets using a different algorithm than the client that way each side has the others decryption algorithm without them having both. This would make decrypting packets coming from the server a lot easier, but the packets being received by the client are not even close to as important as the ones going out as far as a game hacker is concerned. Also, do not use text commands for your protocol, use numbers because they can be harder, although not impossible, to decipher the meaning of (the meaning of a packet whose contents are 101 is not nearly as obvious as if the contents were "killed" instead).
But what about languages like Visual Basic or .NET? Unfortunately, languages like this are especially susceptible to reverse engineering. There are many tools available through the Internet that obfuscate code such that reverse engineering is hard. A simple search for something like ".NET obfuscate" should yield plenty of results.
(While true for Visual Basic earlier than 4, this is not applicable to VB5 and VB6. They both compile to different interpreted code and are as difficult to reverse-engineer as C++. The .NET languages are another story)
While this applies more to genres like MMORPGs and FPSs the theories are the same. Gamers will take advantage of any loophole or bug in your game they can find. For instance, if your AI cannot handle 3D terrain, players could stand on something and rain death down from above on your AI entities.
Static spawn points - if the player or AI entities spawn only at predetermined points, it's easy for players to take advantage of this. In MMORPGs and FPSs this is referred to as "spawn camping". As soon an an entity appears, before they can defend themselves or with them at a severe disadvantage, they're attacked.
Pathing issues - if your AI cannot handle terrain navigation well you could find yourself dealing with players who use this to unfairly combat your AI. For example - your AI will attack players in their line-of-sight. If the player ducks around a corner and the AI no longer sees it, it stops attacking, giving the player the chance to heal himself before jumping back into combat, usually before your AI can do the same.
NOTE: Another term for "spawn camping" is "spawn killing".
Fravia's protection page - This site is hostile to Microsoft products, you have been warned.