January 22, 2012 1 Response

Protecting your numbers against the Cheat Engine

Some time ago the highscore of one of my Flash based ad-game had some miraculous high values, which never could have been achieved through normal game-play. The game code itself had been obfuscated and protected as much as possible and the highscore data had been encrypted before it was send to the server. So the score must have been cheated with a tool like Cheat Engine (which is really incredibly powerful).

So I tried to develop a little AS3 class, which will make cheating a little bit harder at least for the lazy ones.

Here is the “NumberVault” clazz:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package
{
    import flash.utils.clearInterval;
    import flash.utils.Dictionary;
    import flash.utils.setInterval;
 
    /**
     * @author Björn Acker | www.bjoernacker.de
     */
    public class NumberVault
    {
 
        private static var _list:Dictionary = new Dictionary();
        private static var _interval:int = -1;
 
        public static function setNumber(key:*, value:Number):void
        {
            value = Math.round(value * 1000000) / 1000000;
            var s:String = String(value);
            var index:int = s.indexOf(".");
            var d:Number = index == -1 ? 1 : Math.pow(10, int(s.length - index - 1));
            value *= d;
            var x:int = int(Math.random() * (2 * int.MAX_VALUE) - int.MAX_VALUE);
            value ^= x;
            _list[key] = {v: value, x: x, d: d};
        }
 
        public static function getNumber(key:*):Number
        {
            var obj:Object = _list[key];
            if (obj == null)
                throw new Error("Key doesn't exist");
            return Math.round(Number((obj.v ^ int(obj.x)) / obj.d) * 1000000) / 1000000;
        }
 
        public static function clearNumber(key:*):void
        {
            _list[key] = null;
            delete _list[key];
        }
 
        public static function clearAll(key:*):void
        {
            _list = new Dictionary();
        }
 
        public static function shakeNumber(key:*):void
        {
            var obj:Object = _list[key];
            if (obj == null)
                throw new Error("Key doesn't exist");
            var x:int = int(Math.random() * (2 * int.MAX_VALUE) - int.MAX_VALUE);
            obj.v = Math.round(Number((obj.v ^ int(obj.x)) ^ x) * 1000000) / 1000000;
            obj.x = x;
        }
 
        public static function shakeAll():void
        {
            for (var i:String in _list)
                shakeNumber(i);
        }
 
        public static function autoShake(interval:int=100):void
        {
            _interval = setInterval(shakeAll, interval);
        }
 
        public static function stopAutoShake():void
        {
            if (_interval != -1)
            {
                clearInterval(_interval);
                _interval = -1;
            }
        }
    }
}
package
{
	import flash.utils.clearInterval;
	import flash.utils.Dictionary;
	import flash.utils.setInterval;

	/**
	 * @author Björn Acker | www.bjoernacker.de
	 */
	public class NumberVault
	{

		private static var _list:Dictionary = new Dictionary();
		private static var _interval:int = -1;

		public static function setNumber(key:*, value:Number):void
		{
			value = Math.round(value * 1000000) / 1000000;
			var s:String = String(value);
			var index:int = s.indexOf(".");
			var d:Number = index == -1 ? 1 : Math.pow(10, int(s.length - index - 1));
			value *= d;
			var x:int = int(Math.random() * (2 * int.MAX_VALUE) - int.MAX_VALUE);
			value ^= x;
			_list[key] = {v: value, x: x, d: d};
		}

		public static function getNumber(key:*):Number
		{
			var obj:Object = _list[key];
			if (obj == null)
				throw new Error("Key doesn't exist");
			return Math.round(Number((obj.v ^ int(obj.x)) / obj.d) * 1000000) / 1000000;
		}

		public static function clearNumber(key:*):void
		{
			_list[key] = null;
			delete _list[key];
		}

		public static function clearAll(key:*):void
		{
			_list = new Dictionary();
		}

		public static function shakeNumber(key:*):void
		{
			var obj:Object = _list[key];
			if (obj == null)
				throw new Error("Key doesn't exist");
			var x:int = int(Math.random() * (2 * int.MAX_VALUE) - int.MAX_VALUE);
			obj.v = Math.round(Number((obj.v ^ int(obj.x)) ^ x) * 1000000) / 1000000;
			obj.x = x;
		}

		public static function shakeAll():void
		{
			for (var i:String in _list)
				shakeNumber(i);
		}

		public static function autoShake(interval:int=100):void
		{
			_interval = setInterval(shakeAll, interval);
		}

		public static function stopAutoShake():void
		{
			if (_interval != -1)
			{
				clearInterval(_interval);
				_interval = -1;
			}
		}
	}
}

You can only protect Number or int values. You can add a number using the static method NumberVault.setNumber(key, value), e.g.

1
NumberVault.setNumber("score", 100);
NumberVault.setNumber("score", 100);

To read back a value use NumberVault.getNumber(key), e.g.

1
NumberVault.getNumber("score");
NumberVault.getNumber("score");

There are some more methods like NumberVault.autoShake() which will periodically modify the internal value representations.

To e.g. add some value to a number use:

1
NumberVault.setNumber("score", NumberVault.getNumber("score")+100);
NumberVault.setNumber("score", NumberVault.getNumber("score")+100);

 

 

 

Filed in Flash

One Response

  1. Millie on February 2, 2012, 10:43 am

    Thanks alot – your answer solved all my porebmls after several days struggling