13

Background

I've had problems for quite a while now with players cheating in my android game. For a strict single-player game this wouldn't be a big issue, but since my game contains multiplayer battles and global highscore lists, it's causing legit players to stop playing because of the cheaters.

How they cheat

Cheaters use an app for root users called Gamecih. Gamecih lets users pause an app, change variable values, and then resume the app. So in my case they just pause the game, change "health" to 74 trillions and then kick the crap out of everyone on multiplayer. Here's a video showing how Gamecih is used to cheat in Fruit Ninja(not my game).

Considered methods

  1. Code obfuscation. This won't work because obfuscation doesn't change variable values, just variable names. This means that cheaters can still find the variable that has the same value as their current health and then change that variable.
  2. Code obfuscation + getter & setter value changing. This way, health will not actually represent the real health value. In the getter method I would do something like return health*10; and in the setter I would do health=input/10; This could of course be more complicated.

What I want

It could be argued that considered method nr 2 is what I should use, but then again, it doesn't prevent hacking, it just makes it harder. Ideally, I would like to detect when people cheat using Gamecih, display a pop-up saying "Darn you, you nasty hacker", and then close the application. I do not want a server-dependent solution as I would like my players to be able to play while offline as well. If possible, I would also like to avoid code obfuscation.

Emir Kuljanin
  • 3,881
  • 1
  • 25
  • 30
  • I don't know how your game looks like, but most of them got the regular "100 HP"... So why don't you check `if(Player.CurrentHP > 100)`? – SeToY Oct 01 '12 at 09:11
  • 1
    at least you can check the health every second or so and detect if health growed too much or over a specific value, then store hacked=true and never load again ;) – Karussell Oct 01 '12 at 09:11
  • It's an RPG so the health can be very different values. So can gold, armor and other variables. Also, every cheater doesn't change to insane values, some do reasonable changes. So the growth check doesn't work either. – Emir Kuljanin Oct 01 '12 at 09:14
  • 2
    Well, I'd suggest a server-sided check anyway. You should have two modes: Online and Offline. In Online-Mode you got the server-sided check and the results go into the highscores.. you can still play offline, but the scores won't be allowed to show up in the highscores. – SeToY Oct 01 '12 at 09:17
  • eventually (?) you can protect your RAM somehow like it is done here: http://stackoverflow.com/q/960499/194609 ... also instead of the server side solution you could store the variables in the other players game instance or a checksum of that. as a last step you could also contact gamecih and ask if they include you on their blacklist. – Karussell Oct 01 '12 at 09:22
  • When it comes to anti-cheat in any scenario your *only* real option besides full server-side verification of all known variables and drastic changes (ie. protecting your process somehow if even possible in Java..) is security through obscurity. You need to make it as hard as possible, encoding/encrypting the health value whilst in a randomly named variable will make it difficult. Change the variable name with each update etc etc – Rudi Visser Oct 01 '12 at 09:23
  • Ok, how about encrypting the health value? – midhunhk Oct 01 '12 at 12:41

10 Answers10

9

You can store life in X number of variables and the real value will be the sum of them (always calculated dynamically). You randomly choose which one to update. On top of that You can add some consistency check and it becomes extremely hard for cheater to realise what and how to change it.

The consistency check could be a simple rule that 1st, 2nd and 3rd variables are in growing order for example and the 4th is the smallest. It will take someone good while to figure this out with this tool.

Yoy can also get more creative and mix in some encryption etc (the way you mentioned) on top of that. Then it becomes second to impossible unless someone has your code.

EDIT: Add 100 random variables that change all the time with random names (or positions in the array, to make it easier) and then good luck for cheaters looking for the right ones. And make it all dynamic so every time they have to crack it again.

Dharmendra
  • 33,296
  • 22
  • 86
  • 129
bjedrzejewski
  • 2,378
  • 2
  • 25
  • 46
  • This just makes it difficult and not impossible to cheat, right? – midhunhk Oct 01 '12 at 10:13
  • 4
    I think it makes it incredibly difficult. I don't think you can make it impossible without some sort of server check. – bjedrzejewski Oct 01 '12 at 10:16
  • In terms of hack-proof, this is a great answer. Implementing it would be quite complicated because I would have to do it for every variable I don't want the cheater to change. If santirivera92's solution doesn't hold, I'll have to try this out. – Emir Kuljanin Oct 01 '12 at 13:44
  • You can try to define a set of variables that you want to protect. Then write a method that encrypts->decrypts them and check for the consistency. If you manage to develop this kind of framework you can easily drop extra variables inside that you want to secure. The key is a smart (semi-random) consistency check. – bjedrzejewski Oct 01 '12 at 13:46
7

You can check periodically if your value has changed when it was not supposed to.

For example, you can store in a separate hidden flag the fact that the health value has changed. If your check method does detect a change in the value, and the flag is not set, then you can tell that the change was illegal.

For example :

void incrementHealth(int amount) {
    health = health + amout;
    hiddenCheck.hasChanged = true;
    }

and in a separate method which must be invoked periodically :

void checkHealth() {
    if (hiddenCheck.hasChanged) {
        // change is valid
        hiddenCheck.hasChanged = false;
        hiddenCheck.lastKnownValue = health;
        } else {
            if (hiddenCheck.lastKnownValue != health) {
                // An illegal change has occured ! Punish the hacker !
                }
            }
        }
   }
Orabîg
  • 11,718
  • 6
  • 38
  • 58
  • This is a good approach. Make sure that only your code has updated the health value, Do a hash of the current health and store it somewhere (md5 or some algorithm like that), so you can know who changed the variable value. – midhunhk Oct 01 '12 at 13:03
6
try{
    ApplicationInfo info = getPackageManager().
            getApplicationInfo("com.cih.gamecih", 0 );
    return true;
} catch( PackageManager.NameNotFoundException e ){
    return false;
}

If this function returns true, don't even let the hacker enter Multiplayer mode, and prompt him to uninstall it.

Charlie-Blake
  • 10,832
  • 13
  • 55
  • 90
  • 1
    Asking to uninstall the app may not be a good experience. Can we check if that application is running at the moment and deny multiplayer access. That way, they don't have to uninstall that app, but needs to stop it to play the game. Kind of like what the CD / DVD game engines implement – midhunhk Oct 01 '12 at 13:07
  • This is a smart idea and very simple too. I could keep a list on my server over package names to cheating apps and just update it when a new comes out. – Emir Kuljanin Oct 01 '12 at 13:29
  • 1
    This is what I usually do when a user tries to block an ad from my apps ;-) – Charlie-Blake Oct 01 '12 at 13:31
  • 3
    unfortunately, this will not prevent the hacker to use another similar hacking app (or the same one repackaged). This is a very specific solution that won't stand in long-term imho. – Orabîg Oct 01 '12 at 22:24
  • @santirivera92 So you're closing the app when an adblock app is installed? I'd be the first one to uninstall your app to find an alternative on the PlayStore... and the last one to buy the paid ad-free version of your app. – SeToY Oct 02 '12 at 08:55
  • 1
    @SeToY Would you even buy the paid ad-free version in first place? This is my work, and I work to get revenue. I let you use my free app if you see the ads. If I can't get any revenue there's no reason to let you use my app. – Charlie-Blake Oct 02 '12 at 11:40
  • @santirivera92 I'm always evaluating the free version first. When a paid ad-free version exists and I'm confident with the free one, I'm going to buy the paid one. But when I see that your app is teasing the users like that, I'd just use an alternative. – SeToY Oct 02 '12 at 11:47
  • So, you actually do what people should do. Know what? Most people don't. – Charlie-Blake Oct 02 '12 at 12:21
2

The people who are good at cheating games read these forums too, and they know all your little secrets.

There is no solid way to prevent people from cheating a game that stores important variables locally. A game must keep these variables on the server. If these variables are not kept on the server, there will always be someone that can hack your game.

Sepero
  • 4,489
  • 1
  • 28
  • 23
1

Calculate your stats dynamically from a stored value.

private double getSaltedSqrt(int i){
    return Math.sqrt(i)+1337;
}

private int getTrueValue(double i){
    return (i-1337)*(i-1337);
}

This way, no regular-brained human will be able to find your values from RAM ever. Somebody with 100 health will have a health value of 1347.0

If somebody deals 10 damage to that player, you just have to call:

currentHealth = getSaltedSqrt(getTrueValue(currentHealth)-damage);

However, the most secure way to do this, is to implement all those changes via server.

Charlie-Blake
  • 10,832
  • 13
  • 55
  • 90
  • 2
    This kind of software allows you sometimes to just track for changes. For example- you lost some life- the variable changed, so you look at two snapshots in time and see the changed variables. Then you change your life again- drinking a health potion or doing something else in game and look for changes again. After repeating a few times you can find a variable that is changing. This is why it may be good to have a few fake variables to make it harder. – bjedrzejewski Oct 01 '12 at 10:14
  • You can also assign the 1337 variale on startup and make it change everytime the game launches. Anyway, it's just impossible to do this without server checks. – Charlie-Blake Oct 01 '12 at 12:03
  • Also I think the trick is to make it really hard to find the variable- so you need to crack it every time. Agree that you can not make it 100% cheat-proof without server side check. You can just make it difficult enough to discourage people from trying. – bjedrzejewski Oct 01 '12 at 12:06
1

I have a thought on this, since I sometimes use GameCIH myself. You could have a rolling 10-entry transaction log that self-checks on every new transaction.

What you would do (since GameCIH can only deal with one variable at a time) is have two variables that are checked against each other.

  • Original (or 11-ago) value
  • Array of values of changes 1 through 10
  • Summation value, negated. (This totally changes the decimal value you can see, and it'll change differently than the original value when the oldest log entry is rolled into it.)

If the negative of the summation value doesn't match the original plus the 10 logged transactions, return an error.

You would just have to change how your stat mods are handled - if even one of them still tries to modify the original value directly, your game would return that it's been incorrectly changed.

Steamy
  • 11
  • 1
0

To prevent memory cheating you can do one of the following:

Oliver
  • 487
  • 2
  • 9
0

You should store a hash (eg crc32 or md5) of the health etc. everytime you update the value, do a hash check on the currently set value. In this case, the cheaters would have to write a seperate app that handles the hashes. Possible, but this will stop the script-kiddy cheaters soon enough.

mrexodia
  • 648
  • 12
  • 20
0

In the Pokemon games, they used DMA. You could get a similar effect by having a timer go off and trigger an update of all values while the game is paused for very short time. The update would add some random amount to all variables (including the one that you subtract from to get individual values). You can also try having values stored in a large array and change the starting position. Instead of an absolute pointer like GameState[121], you'd have something like GameState[121+StartingPosition] and just combine the value-incrementor with a location randomizer. Modular arithmetic is your friend, in both cases. Be wary of overflowing the array and off-by-one bugs. A buffer overrun would not be good. ;)

If this was a Flash or Java app: Sadly, using memory management to quickly remap the position in RAM of values is not as convenient as in a native binary like the Gameboy Advance uses. Copying all variables to a second set, in a random order, then deleting and garbage-collecting the original values would probably make your game run slow as heck.

The dude
  • 7,896
  • 1
  • 25
  • 50
Joe
  • 11
  • 1
0

Could you just check for root access on game launch? Then deny opening app or deny multiplayer mode on rooted devices? Provide a small check at the opening load screen only when app is initialized, maybe have app request super user then if user grants it try to do a harmless function not allowed without superuser then a code to check if said function was successfully then undo change and pop a message box indicating user should leave root mode try again.

Alternately this check could be applied upon entering multiplayer mode.

Also you could just run multiplayer mode from a server and single player from device and let single players hex edit freely.

Faugaun
  • 33
  • 7