Search Unity

Anti-Cheat Toolkit: stop cheaters easily!

Discussion in 'Assets and Asset Store' started by codestage, Aug 20, 2013.

  1. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey all,
    new 1.5.3.0 version is already available!

    Most important change in this update - plugin is moved to the Plugins folder by default for all supported Unity versions (4.6+).
    Also few user requests were implemented along with some additions.

    1.5.3.0
    - plugin moved to Plugins folder, please remove previous ACTk version!
    - added ObscuredString.Length property for better compatibility
    - added ULong support to the ObscuredPrefs
    - added Decimal support to the ObscuredPrefs
    - added ObscuredUInt inspector output for Unity 5.0+
    - added ObscuredULong inspector output for Unity 5.0+
     
  2. lunstar

    lunstar

    Joined:
    Mar 4, 2015
    Posts:
    8
    I have purchased an asset few days ago and I have a question.
    In our game, we save user's save data's by binarization.
    This work is done through JSON.NET's BsonWriter.

    We have applied ACTk in class that currently maintains the save and applied few parts such as shown.
    Code (CSharp):
    1. public class SaveData {
    2. ...
    3. public ObscuredInt Money { get; set; }
    4. public ObscuredString Name { get; set; }
    5. ...
    6. }

    In addition, binarization is being processed through the code below.
    Code (CSharp):
    1. using (var fs = File.Open (filePath, FileMode.Create)) {
    2.        using (var writer = new BsonWriter (fs)) {
    3.        var serializer = new JsonSerializer ();
    4.        serializer.Serialize (writer, _save);
    5.    }
    6. }
    7.  
    8. using (var fs = File.OpenRead (filePath)) {
    9.     using (var reader = new BsonReader (fs)) {
    10.      var serializer = new JsonSerializer ();
    11.      _save = serializer.Deserialize<SaveData> (reader);
    12.    }
    13. }

    The process in binarization of previous save data and reading it is well applied. However, after changing to a Obscured type, some variables despite having a fixed value, is ultimately read as a {0}.

    Data is read and written through binarization of JSON file, and we're curious on what other method must be used.

    We have solved non-binarization JSON file through manual's converter. However, there are problems when it comes to creating the binary.
     
    Last edited: Jan 24, 2017
  3. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    DanjelRicci likes this.
  4. lunstar

    lunstar

    Joined:
    Mar 4, 2015
    Posts:
    8
  5. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Understood, I'll take a look and will try to reproduce issue on my side or I'll provide working solution for your case.
    Thanks!
     
  6. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey again, @lunstar !

    Just tried the ISerializable and it seems to work fine.

    Here is an example:
    Code (CSharp):
    1.  
    2. using System;
    3. using System.Runtime.Serialization;
    4. using CodeStage.AntiCheat.ObscuredTypes;
    5.  
    6. [Serializable]
    7. public class ClassToSerialize: ISerializable
    8. {
    9.     public ObscuredInt Money { get; set; }
    10.     public ObscuredString Name { get; set; }
    11.  
    12.     public ClassToSerialize() { }
    13.  
    14.     private ClassToSerialize(SerializationInfo info, StreamingContext context)
    15.     {
    16.         Name = (string)info.GetValue("Name", typeof(string));
    17.         Money = (int)info.GetValue("Money", typeof(int));
    18.     }
    19.  
    20.     public void GetObjectData(SerializationInfo info, StreamingContext context)
    21.     {
    22.         info.AddValue("Name", Name);
    23.         info.AddValue("Money", Money);
    24.     }
    25. }
    Or, if you wish to store data in encrypted state, here is a way to do it:

    Code (CSharp):
    1. using System;
    2. using System.Runtime.Serialization;
    3. using CodeStage.AntiCheat.ObscuredTypes;
    4.  
    5. [Serializable]
    6. public class ClassToSerialize: ISerializable
    7. {
    8.     public ObscuredInt Money { get; set; }
    9.     public ObscuredString Name { get; set; }
    10.  
    11.     public ClassToSerialize() { }
    12.  
    13.     private ClassToSerialize(SerializationInfo info, StreamingContext context)
    14.     {
    15.         ObscuredInt loadedMoney = 0;
    16.         ObscuredString loadedName = string.Empty;
    17.  
    18.         loadedName.SetEncrypted((string)info.GetValue("Name", typeof(string)));
    19.         loadedMoney.SetEncrypted((int)info.GetValue("Money", typeof(int)));
    20.  
    21.         Money = loadedMoney;
    22.         Name = loadedName;
    23.     }
    24.  
    25.     public void GetObjectData(SerializationInfo info, StreamingContext context)
    26.     {
    27.         info.AddValue("Name", Name.GetEncrypted());
    28.         info.AddValue("Money", Money.GetEncrypted());
    29.     }
    30. }
    I've tested these examples with Bson (de)serialization code you provided.
    Please let me know if this will work or not work for you.
     
  7. lunstar

    lunstar

    Joined:
    Mar 4, 2015
    Posts:
    8
    Thank you @Dmitriy Yukhanov!
    I've tested ISerializable things. But i've got problems.

    My save class includes dictionary with struct, and many other variables.
    This is my save class applied with ISerializable.

    Code (CSharp):
    1.  
    2. [Serializable]
    3. public class SaveDataModel : ISerializable {
    4.  
    5.     public Dictionary<UserBehaviourCheckType, bool> UserBehaviourChecker;
    6.  
    7.     // Statics
    8.     public Dictionary<GameStatisticType, GameStatisticInfo> GameStatistics;
    9.  
    10.     // Ad
    11.     public bool NoAds = false;
    12.     public int AdCount = 0;
    13.  
    14.     // Option
    15.     public int GraphicQuality = 0;
    16.     public bool MuteBGM = false;
    17.     public bool MuteSFX = false;
    18.     public string Language = "";
    19.  
    20.     // User Information
    21.     public string Username = "";
    22.     public ObscuredString UUID { get; set; }
    23.     public bool RegisteredUserName = false;
    24.  
    25.     // Money
    26.     public ObscuredInt Like { get; set; }
    27.     public ObscuredInt Star { get; set; }
    28.  
    29.  
    30.    ....
    31.  
    32.  
    33.     public Dictionary<int, RegionInfo> Regions;
    34.     public Dictionary<int, PlatformInfo> Platforms;
    35.  
    36.     // Delivery
    37.     public bool OpenMovingMart = false;
    38.     public int DeliveryProgress = 0;
    39.     public List<DeliveryRewardInfo> DeliveryRewards;
    40.  
    41.     public SaveDataModel() {}
    42.     private SaveDataModel(SerializationInfoinfo,StreamingContextcontext){
    43.        ....
    44.     }
    45.     public void GetObjectData(SerializationInfoinfo,StreamingContextcontext){
    46.         ....
    47.     }
    48. }
    I have no solution of getting values of containers (list, dictionary with structs) via ISerializable method.
    Thank you!
     
    Last edited: Jan 26, 2017
  8. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @lunstar

    Alright, back to the JsonConverter =D
    Why does it not working for you?

    I just tried it and it seems to work just fine.
    Looks like you just forgot to add it to your (de)serializers.

    Try to add it after you create JsonSerializer:

    Code (CSharp):
    1. var serializer = new JsonSerializer();
    2. serializer.Converters.Add(new ObscuredValueConverter());
    Also note, mcmorry's example has no ObscuredString implemented, just add it similar way existing types are added to be able to convert ObscuredStrigns.
     
  9. lunstar

    lunstar

    Joined:
    Mar 4, 2015
    Posts:
    8
    Aha! It works!!
    I didn't know the method add converters to JsonSerializer.
    It seems to be working nicely.

    Thank you very much!!
     
    codestage likes this.
  10. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey all, new update 1.5.4.0 available!

    In this update some user requests were implemented.

    1.5.4.0
    - added (x,y) constructor and same Encrypt API to the ObscuredVector2
    - added (x,y,z) constructor and same Encrypt API to the ObscuredVector3
    - added (x,y,z,w) constructor and same Encrypt API to the ObscuredQuaternion
    - added new GetDecrypted API to all obscured memory types
    - added ObscuredShort inspector output for Unity 5.0+
    - fixed incorrect InjectionDetector execution with argument in callback
     
  11. M0rph3v5

    M0rph3v5

    Joined:
    Aug 15, 2012
    Posts:
    24
    About to buy your asset. Looks exactly what I'm looking for. I was wondering if it's easy to make it work with iCloud saves for example?
     
  12. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @M0rph3v5 !

    Unfortunately I never worked with iCloud saves and have no idea on how it works with Unity.
    But ACTk's public APIs allows you to get encrypted data from obscured types, save it and load it back to obscured types for example.
     
  13. M0rph3v5

    M0rph3v5

    Joined:
    Aug 15, 2012
    Posts:
    24
    Thanks for the reply, I'll have to research that too but perhaps you already did something with it. Np! :)
     
  14. ZoneOfTanks

    ZoneOfTanks

    Joined:
    Aug 10, 2014
    Posts:
    128
    Any chance to see some code obfuscation tool in future release? ;)
     
  15. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @abrasive !

    Let me shamelessly copy-paste my recent reply from the reviews section:

    Currently there is already great obfuscator on the store (Obfuscator).
    Implementing it in ACTk would raise ACTk's price for sure and it's currently unwanted change, so currently my TODO list starts with other features I'd like to implement first.
     
  16. Ds777

    Ds777

    Joined:
    Apr 30, 2013
    Posts:
    15
    Apparently I'm getting a false detection on ObscuredCheatingDetector, I'm using several public ObscuredInt in a prefab, If I select several prefabs (same script) and try to edit something (in my case a Shpree Collider radious) it will start showing the detection without doing anything.
    I can solve it if I re-assign the obscured variables in every prefab that I selected and edited at the same time, I do not know if I'm the only one who has this problem.
     
  17. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    @Ds777 thanks for reporting this, I'll take a look and will try to reproduce your issue.
    BTW are you using latest version from the store?
     
  18. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    Hello,

    Just wanted to ask if there is a recommendation on the key lengths. As in the actual value of the key itself. I see that int and string is possible. For int which maps to int32 a value of 2,147,483,647 would be maximum, so anything in that range. For string it could be any length I'm guessing? Longer value add greater protection do they not, but will they effect the performance when encryption or deception operations are taking place.

    Any thoughts you might have on this are appreciated. Thank You for a great plugin.
     
  19. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    Another question. You recommend setting the new Crypto Key, presumably I would want to do this before I declare a variable of Obscured type. What about variables that are part of a class declaration, in this use case I would need to use the ApplyNewCryptoKey in the constructor or other method of the class, right? Just want to make sure this is expected pattern. In the example screen one of these variables would be "obscuredString", because it is declared as part of the class there is no chance to set the encryption key ahead of time. This is not a problem just want to make sure this is expected use.

    Also would you recommend setting a different key for each of the variables in the game? Or is this overkill? For example number of collected coins could have one, current score could use a different key, or is this just making things overly-complicated and won't really provide any additional protection. I'm talking about variables that change constantly and not something like top score that changes seldom for which you recommend using RandomizeCryptoKey.

    Lastly, in the ActTesterGui.cs (lines 64-70) you speak of a small trick to hide encryption key in serialized MonoBehaviour, but I think you're missing the actual [HideInInspector] filed. If that is not the case then I'm not sure what the actual trick is.

    Thank You.
     
    Last edited: Feb 21, 2017
  20. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @JesterGameCraft !

    There is no need in extra long keys here, adding more chars to the string keys will not greatly improve security, but it will need few extra cycles to process a value every time.

    I'd suggest to stick with keys not exceeding 10 chars.

    Yep. To apply new key to the existing instances of obscured types, you'll need to explicitly call an ApplyNewCryptoKey API on them.
    All new instances after crypto key change will have it by default.

    Definitively overkill, but you're free to use RandomizeCryptoKey for the values which change often to defend them from the unknown values search. Just make sure to call RandomizeCryptoKey in the non-constant manner, e.g. with random intervals, even when target value didn't changed.

    Right, in the serialized file. It's pointless to use HideInInspector ther since cheater will not see your inspector. The main idea there - move key from the code which can be decompiled and viewed to the serialized object. It's much harder to find it in the serialized object in the resources of the compiled build.
     
  21. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    Thank You for answering my questions. I had a couple more that I wanted to clarify.

    I've looked over this video https://unity3d.com/learn/tutorials/topics/scripting/persistence-saving-and-loading-data at about 40min mark the serialization technique is used to save and load game data. So if I understand your comment correctly I should serialize my encryption key and that will keep separate from the class definition (class object) source. Then I can just read the key in at game start. Would storing the key at runtime in an obscured type be a good idea?

    On a similar note - when storing my game data - would it be more secure to have a class with Obscured type variables that holds my game data (eg. highest score) and then serialize that class instead of using ObscuredPrefs?
     
  22. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Yes, but you don't need to serialize it directly, Unity serialization engine will make it for you when you'll place it at the ScriptableObject or MonoBehaviour.

    It should work fine, so yes, you may declare ObscuredInt at the MonoBehaviour, set the proper value at the inspector and read it on game start to use as an encryption key.

    Please let me know if it will not work for you for some reason.
     
  23. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    I see, thank you.

    Last thing I wanted to ask, would you recommend I use a class that has Obscured types that hold my game data (eg. high score) and then serialize that class on game save. On game load would deserialize the data. This would be instead of using ObscuredPrefs, or will using ObscuredPrefs will work just as well.

    Thanks again for all the replies, much appreciated. Regards.
     
  24. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Ah, sorry, forgot to answer this part.
    I'd suggest to stick with prefs if you're not going to save hundreds kb of data. It will allow to avoid headache with manual obscured types serialization via converters or ISerializable callbacks.
     
  25. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    Thank You for great plugin and support.
     
  26. RafaelAlcantara

    RafaelAlcantara

    Joined:
    Mar 30, 2016
    Posts:
    11
    @Dmitriy-Yukhanov does your plugin protect our games from Lucky Patcher-like apps?
     
  27. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    @RafaelAlcantara no, currently ACTk has no such feature. It will have rooted devices detection (it's on the TODO) which will partially allow to deal with such tools, but rooted device not always mean cheating customer, so it will be up to you how to react on rooted devices.

    Generally, Lucky Patcher-like tools are on the TODO list, and I'll make deeper investigation on their features and ways we can resist \ detect such cheating in future.
     
  28. JesterGameCraft

    JesterGameCraft

    Joined:
    Feb 26, 2013
    Posts:
    452
    Hi,

    Question about keeping score and in game currency secure. If I use the ObscureType to keep track of my in game currency and score do I also need to make the increment values of ObscuredType. For example, let's say user collects a gem in the game I have a currentGem variable of ObscuredInt to which I add 1. But should the constant "1" also be of ObscuredInt. I mean if hacker changes the "1" to "1000" that would be bad. Do you have any thoughts on this?

    Thank You.

    Regards.
     
  29. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, no, I'd suggest to use Obscured type only when you declare long-term variable.
    To find and modify value in memory, cheater should make few iterations to filter out desired value from dozens of other values in game. So it's more likely pointless to use Obscured types for the increment values in your case.
     
  30. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    Dmitriy, we are experiencing some annoying bug on our side. Unity 5.5.0p4, changing values of ObscuredBool in the game and other types sometimes randomly trigger the ObscuredCheatingDetector. Any ideas why it happens?
     
  31. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @tyomklz

    Is it possible those variables were placed on prefabs \ Scriptable Objects?
     
  32. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    Yeah, it's an object that is a part of a prefab, it has a script and the script has a public obscured boolean. Also I was wrong, sorry, it doesn't even change its value at all, prefab has it as true from the start and the boolean never changes while the game is running. Obscured cheating detector triggers when the boolean is being read during runtime inside of if statement, that's it.
     
  33. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    @tyomklz thanks for detailed reply.

    There is a known bug with obscured variables on prefabs \ scriptable objects which can lead to the internal corruption when multiple prefabs \ SO with Obscured variables in inspector are selected, leading to the ObscuredCheatingDetector false positives.

    The fix is ready, but you'll need to fix all the corrupted prefabs in your project.
    I'm finishing editor script which does this and I'll release micro update with fix and this editor script as soon as possible.
     
  34. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    Sounds great, Dmitriy. Thank you for the quick answer.
     
  35. Nucci

    Nucci

    Joined:
    Sep 23, 2015
    Posts:
    6
    The players managed to hack my game with SB Game Hacker, any solution? Exchanges the variables are Obuscured type and I'm using the ObscuredPrefs.
     
  36. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Nucci!
    What exactly did they hacked?
    Some root-level features of such tools can't be detected from managed code, but I need more details on what was hacked and how it was covered with ACTk to be able to help you, if possible.
     
  37. Nucci

    Nucci

    Joined:
    Sep 23, 2015
    Posts:
    6
    Hey man!

    They hacked the diamonds of the game. To test your anti-cheat, I challenged on my facebook page the players hacking, to my surprise, today an individual posted a photo and confirmed in game that this with everything that can be released with released diamonds. The code is implemented as follows:

    http://pastebin.com/kAHKEQj3

    When asked they said they hacked using the SB Game Hacker and another one with Hack App Data, except that this second I could not confirm. Could you help me?
     
  38. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Nucci !

    Did you tried to use RandomizeCryptoKey API to make it harder to find values with unknown value search?
    Also, did you tried to use ObscuredCheatingDetector?
    Finally, did you changed default crypto key?

    Also, I'd like to make it clear - ACTk is not a thing to challenge, it can be hacked, as anything else on client side.
    Its goal not to prevent cheating and hacking in 100% cases, but to dramatically reduce amount of cheating people and \ or to catch the cheating gamers, depending on the features you're using.
    Or you may use it as a good starting point for your anti-cheat systems since ACTk has sources included and you're free to modify it as you like for your game.
     
    hopeful likes this.
  39. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    For some reason my Unity 5.5.2p1 stores PlayerPrefs into another location now (look at the attached screenshot). As a result ACTk's ObscuredPrefs viewer UI doesn't work anymore as it doesn't show any stored data now.

    upload_2017-3-8_4-45-57.png
     
    codestage likes this.
  40. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @tyomklz !

    Thanks for reporting this.
    It's a known issue to be fixed with next update. Unity 5.5+ changed default path for the prefs keys on Windows.
    Here is a fix in case you don't wish to wait for update:
    Replace line 616 of the ActPrefsEditor.cs file
    with this line:
    RegistryKey registryLocation = Registry.CurrentUser.CreateSubKey("Software\\Unity\\UnityEditor\\" + PlayerSettings.companyName + "\\" + PlayerSettings.productName);
     
  41. M0rph3v5

    M0rph3v5

    Joined:
    Aug 15, 2012
    Posts:
    24
    Hey dmitriy,

    Just bought it! I was trying to use ObscuredFloat (using serialization) but the SetEncrypted requires an integer, same goes for GetEncrypted returns an int. I'm guessing this is a mistake copy paste? ;)

    Cheers
     
  42. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @M0rph3v5

    It's fine, floats are encrypted to the integers (both float and int are 4-bytes types).
     
  43. dev_2051

    dev_2051

    Joined:
    Jul 25, 2013
    Posts:
    92
    Hi,
    I spent two days debugging my game just to find out that ObscuredFloat stored on prefabs are always returning 0 or eXX in Awake on Unity 5.4.5:confused::confused::confused: using latest version of ACTK V_1.5.4.0 available on store.
    Please can you suggest what is happening as in unity 5.3.7 ObscuredFloat were returning correct values,it's a major game breaking change for me:(:(:( ,any quick fix will be highly welcomed as it has halted my game testing.
     
  44. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @dev_2051

    Did you updated ACTk as well, or you updated only Unity?
     
  45. dev_2051

    dev_2051

    Joined:
    Jul 25, 2013
    Posts:
    92
    Yes i am using latest 1.5.4.0 version downloaded from asset store
     
  46. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    I mean, from what ACTk version did you updated?
    It's possible you're facing known issue with Obscured types on prefabs which is already solved in current dev version.
    I'm sending you PM with link to the current dev version to let you check if it solves your issue.
     
  47. Kanos

    Kanos

    Joined:
    Jun 17, 2015
    Posts:
    15
    Hi,
    Just wondering when 1.5.5 will be available from the asset store.
    I updated to 1.5.4.0 , and I am experiencing problems with the obscured cheating detector. Never had these problems before. My code has not changed, but the detector is firing on floats alot.
    Previously the float epsilon was 0.0001.
    Now I have to set it to 0.1 to stop false positives.
    Other than that great product :)
     
  48. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Kanos !
    1.5.5.0 is passing a review right now, should be in store in few days I believe.
     
  49. Kanos

    Kanos

    Joined:
    Jun 17, 2015
    Posts:
    15
    Awesome !
     
  50. M0rph3v5

    M0rph3v5

    Joined:
    Aug 15, 2012
    Posts:
    24
    Hey Dmitriy,

    I'm trying to edit a ObscuredString from a editor script using SerializedProperty. However I cannot use a .objectReferenceValue or .stringValue . Any idea how you are able to use editor scripts to save values this way?