Skip to main content
Version: 2024.1.17 🚧

Anti-Cheating Techniques

When integrating with Skillz it is extremely important to take precautions against potential cheating in a game. To give themselves an unfair advantage, players may attempt to use 3rd party tools to modify scores or important gameplay values like health and ammo. The Skillz platform implements a range of technologies and processes to help prevent cheating as much as possible. To maintain a fair and competitive gameplay experience, we also recommend that developers take anti-cheating measures before going live with Skillz.

Cheating Through Memory Modification

One technique for cheating involves modifying values in runtime memory. Using this technique, it would be possible for a user to modify their score before submitting to Skillz or to rig gameplay variables, like health or time, to give themselves an unfair advantage.

This technique works by searching memory for known values. For instance, say the player knew the score was 19, he could search the memory space of the application for a value of 19. This would most likely give him a lot of memory addresses, one of which could be the score value. At that point, there would likely be too many possibilities to reasonably identify which is the score. But if he then did something in-game to increase his score, say to 20, he could then search for 20 in the memory space and so reduce the number of memory addresses that are candidates.

This process could then be repeated until the probable addresses for scores are reduced to one. The cheater would then be able to modify that memory address directly and change the score.

This YouTube video is a good demonstration of the process.

We recommend that game developers employ the techniques listed below. Keep in mind that protecting against cheating is never going to be absolute. Like most security measures it is about making things more difficult for cheaters. There's an old adage about security that says "if you build a higher wall, they build a taller ladder". But by continually re-evaluating and adopting newer techniques to protect your game, you can make it that much harder for potential cheaters.

This is not a comprehensive overview of all forms of anti-cheat protection, and you may decide to use other anti-cheat techniques in your app as appropriate. If you suspect players are cheating in your game, please reach out directly to Skillz and we will work with you to get cheaters out of your game.

Duplicate and Verify Data

One technique to protect memory from being modified is to duplicate and verify data. The idea is to copy key data into separate variables and then compare the copy to the original, if the two don't match at any point in your game, it's likely that someone is cheating.

This ensures there are at least two places in memory that both have to be modified to cheat.

Example Code

private int score = 0;
private int scoreCheck = 0;

// Make sure score and scoreCheck start at the same number
void Awake()
{
scoreCheck = score;
}

// Any code that alters the score should also alter the scoreCheck
private void AddScore(int increase)
{
score += increase;
scoreCheck += increase;
}

// Accessors just need to return the real score
private int GetScore ()
{
return score;
}

// Assume this is your in-game function triggered upon
// finishing the game (eg: time runs out, no more moves)
private void GameOver()
{
if (ConfirmScoreValidity())
{
// The score matches the copy, so report it
SkillzCrossPlatform.ReportFinalScore(score);
}
else
{
// Abort the match because suspicious behavior was detected
SkillzCrossPlatform.AbortMatch();
}
}

// Confirms that the score is valid.
private bool ConfirmScoreValidity()
{
return score == scoreCheck;
}

Obfuscate Data

Another technique to protect memory from being modified is to obfuscate data. Obfuscating or encrypting key data is possible through various means. Before writing to memory, either obfuscate a variable or encrypt it. There are various techniques for achieving this, ranging from a simple XOR to more complex encryption methods. If you are combining this with a duplication technique you could even hash the duplicate and incorporate the hash check into the verify logic, as well as apply completely different obfuscation methods to each copy of the data.

Obfuscating your data will ensure that it is harder for a cheater to find key variables in memory.

Example Code

private int xorCode = 12345; // USE A DIFFERENT XOR VALUE THAN THIS!
private int score = 0;

// Make sure to xor the initial score
void Awake() {
score = score ^ xorCode;
}

// Functions and mutators should xor the value before using it, and xor
// the value again before the function exits
private void AddScore(int increase) {
score ^= xorCode;
score += increase;
score ^= xorCode;
}

// Accessors just need to return the xor'd value
private int GetScore () {
return score ^ xorCode;
}

Advanced Data Protection

You can combine the data-duplication and obfuscation techniques for added security. Ideally you should use a different XOR hash for the score and scoreCheck values. That will make it harder for a cheater to notice, otherwise the memory addresses will contain matching values and make it easier to find your checksum.

Example Code

private int xorCode = 12345; // USE A DIFFERENT XOR VALUE THAN THIS!
private int scoreCheckXorCode = 54321; // USE A DIFFERENT XOR VALUE THAN THIS!
private int score = 0;
private int scoreCheck = 0;

// Make sure to xor the initial values
@Override
private void onCreate(Bundle savedInstanceState) {
score = score ^ xorCode;
scoreCheck = scoreCheck ^ scoreCheckXorCode;
}

// Functions and mutators should xor the value before using it, and xor the value again before the function exits
private void addScore(int increase) {
score ^= xorCode;
score += increase;
score ^= xorCode;
scoreCheck ^= scoreCheckXorCode;
scoreCheck += increase;
scoreCheck ^= scoreCheckXorCode;
}

// Confirms that the score is valid.
private boolean confirmScoreValidity() {
return (score ^ xorCode) == (scoreCheck ^ scoreCheckXorCode);
}