35
\$\begingroup\$

I'm assuming we're talking about desktop games -- something the player downloads and runs on their local computer. Many are the memory editors that allow you to detect and freeze values, like your player's health.

How do you prevent cheating via memory-modifiation? What strategies are effective to combat this kind of cheating?

For reference, I know that players can: - Search for something by value or range - Search for something that changed value - Set memory values - Freeze memory values

I'm looking for some good ones. Two I use that are mediocre are:

  • Displaying values as a percentage instead of the number (eg. 46/50 = 92% health)
  • A low-level class that holds values in an array and moves them with each change. (For example, instead of an int, I have a class that's an array of ints, and whenever the value changes, I use a different, randomly-chosen array item to hold the value)

The game is offline, free and single-player.

Edit: for posterity, I solved this (in C#) and posted my solution here, on my blog.

\$\endgroup\$
0

11 Answers 11

21
\$\begingroup\$

Another possibility (for integer values) is to have a second member-variable which holds a bitwise complement of an existing variable.

So imagine you got health, you would also have healthComplement. Your implementation could look like this:

// setter sets value and complement
void setHealth(int value){
    health = value;
    healthComplement = ~value;
}

// getter checks if value was changed outside of the setter
int getHealth(){
    if(value != ~healthComplement){
        // launch some cheat-counter-measure, like crashing the game?
        exit;
    }
    return health;
}

Somebody who wants to cheat would have to set health and healthComplement correctly, otherwise the game would crash.

I think it's kinda pointless to try to prevent stuff like this. People have successfully created hacks/cheats for much more complex stuff and it just needlessly obfuscates your code or makes your game perform worse.

\$\endgroup\$
0
12
\$\begingroup\$

Here's one scheme I came up with when someone was asking for it on some board long ago. Using percentages or doubled variables doesn't really work, as you can search for "any" values and freeze them.

Instead, make a monster of a data type.

Basically, store your important values as a structure with:

  • 32 pointers to bits
  • For quick reading, have the struct include the current value as a plain int too

For manipulation, collect the current value from the separately-allocated bits (which can be true/false ints), change the value, and then store them back.

Here's the nasty bit: every time you manipulate the value, free and allocate the bits again. Allocation should happen in random order, so the data jumps around in memory and can't be easily frozen.

Additional safeguards would be to store checksums of the values (as well as the "plain" int) and compare these during the manipulation calls too. If mismatch is found, do something subtle, like remove a random key needed to unlock doors to progress in the game.

Edit: For further memory movement, make sure you allocate the new "bits" before freeing the old ones.

Edit: For multiplayer games, it's also possible to serialize the data structure, compress it, and send it over the network. Not the most efficient use of the network, but definitely harder to figure out through packet sniffing.

\$\endgroup\$
0
9
\$\begingroup\$

How about you store the health complemented with a random value generated each time you store it. This would at least defeat the simple mechanism of searching for increasing/decreasing values in memory to find the health.

class Player
{
  int m_Health;
  int m_RandomHealth;
  Random m_Rnd = new Random();

  public int Health {
    get
    {
      return m_Health ^ m_RandomHealth;
    }

    set
    {
      m_RandomHealth = m_Rnd.Next();
      m_Health = value ^ m_RandomHealth;
    }
  }
}

In addition, you might want to reset the value each frame, even if the health doesn't change. This will prevent people from searching for changed addresses when their health changes and that stay the same when their health stays the same.

Bonus: Create a new object each time it changes so the memory addresess change, and set the health to change the random number, xored value, and address in memory every time you read it:

class Player
{
  int [] m_HealthArray; // [0] is random int, [1] is xored health
  Random m_Rnd = new Random();

  public Player() {
    this.Health = 100;
  }

  public int Health {
    get
    {
      int health = m_HealthArray[0] ^ m_HealthArray[1];
      Health = health; // reset to move in memory and change xor value
      return health;
    }

    set
    {
      m_HealthArray = new int[2];
      m_HealthArray[0] = m_Rnd.Next();
      m_HealthArray[1] = m_HealthArray[0] ^ value;
    }
  }
}
\$\endgroup\$
0
8
\$\begingroup\$

Although I made the first comment questioning the point of degrading the experience of a portion of your audience for no apparent gain, I still find it an interesting question from a technical point of view.

I just had this idea: What cheaters do is find values that change and freeze them. The search would then happen only between deaths or events that changed the player's health. Moreover, the cheater could be refining the search by filtering out what changed when he was "not dying".

What if the "health" counter is changing the whole time? Make it a pointer and reallocate it every frame or every N frames if the performance hit is too big. Or XOR it with a random value that changes every frame (XORing again against the same value for decrypting before encrypting with a new random value).

If you have other in-game data also changing the whole time (including x and y positions of the player character, or the time counter), that might make it harder to find out which of all the changing data is the health. And freezing the whole game state is a no-go for the cheater.

For further mislead, you can actually store the health in a plain write-only variable meant as a honey pot.

Edit:

Still, the cheater might try to find which of the variables that is changing the whole time is the one to freeze through trial and error. A possible solution would be to couple the variables together.

An example:

Instead of storing health (h) and position (x), you store them in two variables a and b, from which you can retrieve the values later:

a = x+h; b = x-h
x = (a+b)/2; h = (a-b)/2

This way, if the cheater freezes only one of them and then moves the character, the position is affected and, depending on which one was frozen, h goes negative (instant death). You can switch between the above formulas and:

a = x-h; b = x+h
x = (a+b)/2; h = (b-a)/2

In consecutive frames, and you guarantee that in at most 2 frames after either one of the variables have been frozen health will turn 0 the moment x changes. Remember that you are storing only a and b. Combine this with the continuous XOR as mentioned above. The result is a collection of variables that are changing every frame to seemingly random values, and freezing any single one or a subset of them only produces undesired side effects in the game, instant death being one of them.

\$\endgroup\$
7
\$\begingroup\$

One possible option I think might work (I'm not too familiar with these cheating tools): don't hide it. Perform your operations and expect certain results. After the operation (possibly next frame), check to ensure that the results are as you expect them to be. If you subtract health and then verify it, only to find health never changed, you can be pretty sure (provided you don't have some obscure bug) that it was locked.

If you detect cheating, you are now free to change the rules of the game as you see fit for maximum griefing, if that is your intent. If your intent is to ignore the cheating and have the game continue to work, reallocate the health elsewhere in memory and change your pointers so that the new value gets used and the old is ignored. Repeat ad infinitum.

\$\endgroup\$
6
\$\begingroup\$

Any attempts at mere obfuscation are bound to fail in theory, but in practice you just need to make it hard enough to break that the challenge becomes less fun than succeeding at the game. I don’t know what your game is, so I won’t risk suggesting data obfuscation methods, even less as I believe they’re pointless.

That said, and you will probably not be fond of it, I believe you are looking for memory curtaining, which is a Trusted Computing concept.

\$\endgroup\$
0
3
\$\begingroup\$

One very effective technique used by some roguelikes (DoomRL, Brogue) is to mask the actual variables. What this means is that instead of showing health as "2/10," show it as "20%."

Remember, most memory editors work well with specific value searching/filtering. If you don't know the specific value, you can still track it down (eg. search for changed/decreased values after the player health drops), albeit it takes much longer to do it that way.

I also suggest an anti-cheat backlash. For example, if you have a game where the player takes non-positive damage and their health didn't drop, you can easily and accurately check this and know that the player cheats. Do something interesting, like spawning some uber enemies around him :)

\$\endgroup\$
2
\$\begingroup\$

Write a ring 0 driver that hooks SSDT and logs / blocks when ReadProcessMemory / WriteProcessMemory is called on your application. It'd be better to just log so you can slowly change their game behavior over time rather than just crash.

\$\endgroup\$
1
  • \$\begingroup\$ It sounds like you're talking about low-level implementation details (Windows API?) I'm asking about general, high-level strategies. \$\endgroup\$
    – ashes999
    May 22, 2015 at 13:50
2
\$\begingroup\$

Why would you prevent players from cheating themselves (which cheating in a single player game amounts to)? In a multiplayer environment, it's the server's task to detect unnatural changes and counter them (typically by either ignoring the input or blocking the culprit out from the server completely), but in a single player environment there's nothing happening except the cheater is doing himself a disservice.

IOW, unless you're creating a multiplayer game it's a waste of money, and if you are you're thinking of hardening the wrong place.

\$\endgroup\$
2
\$\begingroup\$

Research the known cheating tools - and frequently check whether any of the most common ones are detected running (check process names?)

If any are detected, let the player cheat (if offline, it's harmless), but make sure no scores/acheivements will be posted to any online leaderboard/acheivement system - just make it silently fail?

Won't stop more determined hackers, but will reduce the chance of more casual cheats messing up your leaderboards.

(Might annoy coders that have dev tools open and minimized for legit purposes and are taking a gaming break, though...)

\$\endgroup\$
1
  • 7
    \$\begingroup\$ I was a big fan of Steam as a distribution platform, and played a lot of Team Fortress II a couple of years ago. One evening, I took a break from a long coding session and left open Visual Studio and a debugger while I played. I found myself banned from TF2 for "cheating." No appeal, no framework in place to have a ban lifted. One "offense" and it is permanent for the account. I'd still have no idea why -- and believe me, I was fuming -- except that I saw buried deep in a FAQ that having a "memory editor" open while playing the game constituted cheating and was ban-able. Wow. \$\endgroup\$
    – user16782
    Jun 3, 2012 at 3:03
1
\$\begingroup\$

I think the simplest solution to this is to implement a cheat option. Disable scoring while in cheat option.

Another good idea, that I have no idea how you would implement. Is to shut off the game when there is a frozen memory variable or something like that :)

Good luck (Y)

\$\endgroup\$
1
  • 3
    \$\begingroup\$ Implementing cheats is a good option. Shutting off the game, not so much... (imagine if you get this wrong, and shut down a legitimate player.) \$\endgroup\$
    – ashes999
    May 22, 2015 at 13:49

Not the answer you're looking for? Browse other questions tagged .