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
// Make sure score and scoreCheck start at the same number
- (id)init {
self = [super init];
if (self) {
score = 0;
scoreCheck = 0;
}
}
// Any code that alters the score should also alter the scoreCheck
- (void) addScore: (int) increase {
score += increase;
scoreCheck += increase;
}
// Accessors just need to return the real score
- (int) getScore {
return score;
}
// Assume this is your in-game function triggered upon
// finishing the game (eg: time runs out, no more moves)
- (void)gameOver {
if([self confirmScoreValidity]) {
// The score matches the copy, so report it
[[Skillz skillzInstance] displayTournamentResultsWithScore:score
withCompletion:^{
// Code in this block is called when exiting to Skillz
// and reporting the score.
NSLog(@"Successfully reported score to Skillz!");
}];
} else {
// Abort the match because suspicious behavior was detected
[[Skillz skillzInstance] notifyPlayerAbortWithCompletion:^{
// Code in this block is called when exiting to Skillz
// as a player abort.
NSLog(@"Player aborted");
}];
}
}
// Confirms that the score is valid.
- (Boolean) confirmScoreValidity {
return score == scoreCheck;
}
private int score = 0;
private int scoreCheck = 0;
// Make sure score and scoreCheck start at the same number
@Override
private void onCreate(Bundle savedInstanceState) {
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
Skillz.reportScore(this, BigInteger.valueOf(score), Skillz.getMatchInfo(this).getId());
finish();
} else {
// Abort the match because suspicious behavior was detected
Skillz.abortMatch(this, Skillz.getMatchInfo(this).getId());
finish();
}
}
// Confirms that the score is valid.
private boolean confirmScoreValidity() {
return score == scoreCheck;
}
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;
}