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
    Already done! =)
    Just sent new update for review.
     
  2. mog-mog-mog

    mog-mog-mog

    Joined:
    Feb 12, 2014
    Posts:
    266
    perfect, great support :)
     
  3. Masashi-Wada

    Masashi-Wada

    Joined:
    Jul 6, 2010
    Posts:
    89
    Your product is very wonderful.

    However, I have an problem and wish protection of the value of DateTime.
    For example, in order for it to prevent rewinding the time of a daily bonus.
    Is there any good idea which protects the value of DateTime by the current version?
     
  4. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, Masashi!
    DateTime is pretty complex type and I'm not sure I'll add it to the Obscured types in near future.
    However, you may use DateTime.ticks or DateTime.toBinary() to store date in ObscuredLong variable preventing it from cheating. Just like this (super simple draft example):

    Code (CSharp):
    1. private void Start()
    2. {
    3.     // store like this
    4.     ObscuredLong timeLeftBeforeDailyBonus = loadTimeBeforeBonus().ToBinary();
    5.  
    6.     // operate like this
    7.     DateTime timeLeft = DateTime.FromBinary(timeLeftBeforeDailyBonus);
    8.  
    9.     // do anything with date
    10.     timeLeft = timeLeft.AddMinutes(-1);
    11.     timeLeft = timeLeft.AddYears(-208);
    12.  
    13.     // encrypt it back to store in secure form
    14.     timeLeftBeforeDailyBonus = timeLeft.ToBinary();
    15.  
    16.     // outputs "11/11/2014 11:10:11 AM"
    17.     Debug.Log(DateTime.FromBinary(timeLeftBeforeDailyBonus));
    18. }
    19.  
    20. private DateTime loadTimeBeforeBonus()
    21. {
    22.     return new DateTime(/*dummy*/2222,11,11,11,11,11);
    23. }
     
  5. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Meanwhile, Anti-Cheat Toolkit 1.3.1 was released on Asset Store!
    Most important changes were made in SpeedHackDetector, not it even more reliable and flexible! I wish to thank Cliff Cawley for his feature requests and suggestions on SpeedHackDetector.
    There are some other important changes and fixes in this update as well, see yourself:

    1.3.1
    - ObscuredBool inspector support added (requires Unity 4.5)
    - new public API for all basic Obscured types: ApplyNewCryptoKey(), see docs for more details
    - Significant changes in SpeedHackDetector:
    * Cool Down system introduced. Read more in pdf and "coolDown" field API docs (thanks Cliff Cawley)
    * detection checks period is not affected by speed hack anymore (now it uses system date timer)
    * fixed speed hack wasn't detected in some cases
    * fixed false positives in some cases
    * fixed extra calculations on first detection check in the SpeedHackDetector
    * fixed incorrect datetime change detection
    * fixed continuous detects after first detect even if speed hack was removed (thanks Cliff Cawley)
    * speed hack detection log message now appears in debug builds only
    * application pause handled correctly now
    - all basic Obscured types are serializable now (only binary serialization supported)
    - ObscuredBool cheating detection is now supported in the Flash Player.
    - fixed ObscuredInt default value issues
    - fixed null reference error while using exposed ObscuredFloat fields to the inspector without default value
    - fixed incorrectly decrypted ObscuredString values in inspector when used without default values
    - fixed cheating detection false positives for Obscured variables while being exposed to the editor
    - fixed possible cheating detection false positives for ObscuredVector2, ObscuredVector3 and ObscuredQuaternion
    - fixed GetEncrypted() after SetNewCryptoKey() in ObscuredString didn't counted new crypto key
    - removed redundant [InitializeOnLoad] attribute from ActPostprocessor
    - minor refactorings in all Obscured types
    - fixes and additions in the docs

    Currently I'm working on 1.3.2 bugfix update which will fix some more cheating detection false positives in obscured vectors and quaternions in some cases.

    Have fun!
     
  6. Masashi-Wada

    Masashi-Wada

    Joined:
    Jul 6, 2010
    Posts:
    89
    Sounds good.
    I want protection of DateTime to be added officially.

    Thank you!!
     
  7. backwheelbates

    backwheelbates

    Joined:
    Jan 14, 2014
    Posts:
    232
    Just curious, what happens when you are accessing an Obscured type, and its been modified, or for some reason, its not able to decode it?

    Does it still return a value? or does it return a Null? Is there a global, isHacked variable that gets triggered?

    Thanks!!
     
  8. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    @Eric_Bates Hey, if cheater will try to modify encrypted value, he will just get trash after decryption.
    But more likely cheater will modify fake unencrypted value and it will be detected if ObscuredCheatingDetector is started.
     
  9. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Another update is at the Asset Store!
    Mostly fixes inside:

    1.3.2.1
    - optimized inspector exposition for supported obscured types
    - fixed array elements names while exposing ObscuredString[] in inspector
    - fixed ObscuredString truncation while being shown at inspector in some cases (thanks Stefan Laubenberger)

    1.3.2
    - ObscuredVector2, ObscuredVector3 and ObscuredQuaternion accuracy increased (consistent on all platforms now)
    - added epsilons for ObscuredFloat, Obscured vectors and ObscuredQuaternion in ObscuredCheatDetector
    - fixed cheating detection false positives for Obscured vectors and ObscuredQuaternion (thanks Capital j Media)
    - fixed ObscuredInt returned 0 in case value matched crypto key regression
    - minor optimizations and refactorings
     
  10. g8minhquan

    g8minhquan

    Joined:
    Jun 18, 2014
    Posts:
    38
    Hi Dmitriy, this sounds like an awesome asset.
    Do every features work on all mobile platforms?
     
  11. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @g8minhquan!
    All features except the InjectionDetector should work on all mobile platforms, InjectionDetector works and tested only on Android and iOS mobiles.

    All other features tested on iOS and Android mobiles as well, but should work fine on all mobile platforms.
     
  12. g8minhquan

    g8minhquan

    Joined:
    Jun 18, 2014
    Posts:
    38
    Thanks for the info. What I understand is that currently all features works on iOS and Android, but some feature may not run on other mobile platforms like Blackberry and Windows Phone. Is that correct?
     
  13. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Yes, it is.
     
  14. thi-donada

    thi-donada

    Joined:
    Apr 23, 2014
    Posts:
    17
    Hello Dmitriy,

    It's probably a newbie question, or i'm doing something wrong but here i go:
    Whenever i run my game on the editor for the first time after opening Unity i get a
    Null reference exception when i try to get the device ID.
    I guess it happens because since it's the editor, it can't get a device ID, or i'm doing something wrong,
    I'm not at my workstation right now, so if you want i'll provide more information later on.
     
  15. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @thi.donada!
    Could you please describe how you;re trying to get DeviceID? It should work fine in Editor.
    And where does the null error happens, on what line in what file (callstack would help here)?
     
  16. thi-donada

    thi-donada

    Joined:
    Apr 23, 2014
    Posts:
    17
    The error happens in the ObscuredPrefs.cs file, at line 737:

    if(String.IsNullOrEmpty(deviceID)) deviceID = SystemInfo.deviceUniqueIdentifier;

    It Happens when in a scene when i use Obscured.Prefs.ForceLockToDeviceInit();

    Happens in another scene too when i use ObscuredPrefs.lockToDevice = ObscuredPrefs.DeviceLockLevel.Strict;

    In both cases i'm doing it on Start().
    It gives null reference exception, only the first time when i hit play in the editor.

    Thanks in advance!
     
  17. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey again!
    Wow, it looks really weird! =\
    I did tried to repeat it myself on both PC and MAC without any luck.
    Did you tried to repeat it on empty project?
    Is it possible to receive your project for further debugging on my side?

    Thanks!
     
  18. thi-donada

    thi-donada

    Joined:
    Apr 23, 2014
    Posts:
    17
    Yes, i reproduced it in an empty project.
    Do you have an email which i can send the project to you?
     
  19. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Sure, focus[AT]codestage.ru. It should be mentioned in the readme.pdf (in latest plugin version) as well.
     
  20. thi-donada

    thi-donada

    Joined:
    Apr 23, 2014
    Posts:
    17
    I've sent you an Example Project in the email
     
  21. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Huge thanks for your email!
    Congratulations, you just faced one of numerous Unity bugs! =)

    Here is my investigation results:

    Something strange happens after Play mode start - Game panel got resized and it leads to the MonoBehaviour.Start() method got called on every Editor.OnGUI() call somehow.

    I tried to remove ACT from project and write this at the Start() method:
    Code (CSharp):
    1.     void Start ()
    2.     {
    3.         Debug.Log("Application.isPlaying = " + Application.isPlaying);
    4.         Debug.Log("SystemInfo.deviceUniqueIdentifier = " + SystemInfo.deviceUniqueIdentifier);
    5.     }
    Result: http://i.imgur.com/I3XyVYd.png
    It still throws errors on SystemInfo.deviceUniqueIdentifier read attempt few times before processing it normally.

    Workaround: change layout to the 2 by 3.
    Bug reported!

    EDIT: @gediminasp yey, thanks!
     
    Last edited: Jul 18, 2014
  22. thi-donada

    thi-donada

    Joined:
    Apr 23, 2014
    Posts:
    17
    Oh my, it's just something crazy and totaly unrelated with ACT.
    The problem is really the window getting resized because if you disable Maximize on Play
    the bug doesn't happen.
    Thanks for your help.
     
  23. gediminasp

    gediminasp

    QA Minion

    Joined:
    Feb 27, 2014
    Posts:
    2
    Hey,

    Thanks for reporting this issue! We have forwarded the case to developers.

    Kind regards,
    Gediminas
    QA team
     
  24. LoDx

    LoDx

    Joined:
    Feb 13, 2013
    Posts:
    67
    Hi Dmitriy ,
    Nice work for the asset.

    Alright, pardon me if I missed out somewhere...I've read the readme file several times, but just could not locate and get it right....what would be the correct function/code to call for ReadSavedGame() ?
    - I tried to retrieve variables saved using ObscuredPrefs, but console error message shows :-
    error CS1501: No overload for method `ReadSavedGame' takes `0' arguments​

    **I was using the example script ObscuredPrefsTest.cs as reference, and I tried to call the function ReadSavedGame(); from another script, to retrieve saved variables, but it return the above error. **

    Thanks for your kind time.
     
  25. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, LoDx!
    There is no such method in ACT. Could you please let me know where I mention it? I'm sorry if I confused you somehow.
    To save and read your data just use ObscuredPrefs.Set* / ObscuredPrefs.Get* methods, just like with regular PlayePrefs.
     
  26. mcmorry

    mcmorry

    Joined:
    Dec 2, 2012
    Posts:
    580
    Hi Dmitriy,
    I tried to use some ObscuredInt inside a class that I serialize to json for data transfer with our server. But the int value is serialized as an empty object {}. Would be good to convert directly to string the unobscured value. I'm currently using Json.NET and I'm wondering if you already resolved this before.
    Thank you.
     
  27. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @mcmorry!
    Only binary serialization of Obscured types supported ATM. It may change in future releases though.
    For now you should cast obscured variable to regular type if you wish to process it on server side or take encrypted value using GetEncrypted() if you wish to save value on server without processing it.
     
  28. mcmorry

    mcmorry

    Joined:
    Dec 2, 2012
    Posts:
    580
    I managed to create a custom JsonConverter. Here is the code in case someone else will have the same need:

    Code (CSharp):
    1.  
    2. public class ObscuredValueConverter : JsonConverter {
    3.  
    4.         private readonly Type[] _types;
    5.  
    6.         public ObscuredValueConverter(params Type[] types) {
    7.             _types = types;
    8.         }
    9.  
    10.         #region implemented abstract members of JsonConverter
    11.  
    12.         public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
    13.             writer.WriteValue(value.ToString());
    14.         }
    15.  
    16.         public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
    17.             throw new NotImplementedException();
    18.         }
    19.  
    20.         public override bool CanConvert(Type objectType) {
    21.             return _types.Any(t => t == objectType);
    22.         }
    23.  
    24.         #endregion
    25.     }
    And to use it:

    Code (CSharp):
    1. string json = JsonConvert.SerializeObject(s, new ObscuredValueConverter(typeof(ObscuredInt)));
     
    codestage likes this.
  29. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
  30. mog-mog-mog

    mog-mog-mog

    Joined:
    Feb 12, 2014
    Posts:
    266
    Does it support code obfuscation as well? I have my client keys as Obscured string in my billing file. I am looking for ways to obfuscate all billing cs files, can I do that with this plugin? What's the recommended way? Thank you for the great plugin.
     
  31. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, not for now. It's in my TODO, but not possible to implement ATM, I'm waiting for valid post-process attribute in new versions of Unity (Unity guys are aware about it and going to implement it in Unity 5.x release).

    For now I'd suggest this way:

    1. Use ObscuredString to encrypt your key.
    2. Get encrypted value using GetEncrypted() and encode it with Base64 (to keep it readable).
    3. Declare public string variables for encrypted keys in any mono behaviour added to object in scene.
    4. Set Base64 encoded value in the inspector.
    5. In runtime decode Base64 and use ObscuredString.SetEncrypted() to init your keys.

    Example:
    Part 1. Hiding your key.

    Code (CSharp):
    1.     private void Awake()
    2.     {
    3.         ObscuredString key = "My secret key";
    4.         string encryptedKey = key.GetEncrypted();
    5.         string encodedKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(encryptedKey));
    6.  
    7.         // eU0UQlFXRlRAFF9UTQ==
    8.         Debug.Log(encodedKey);
    9.     }
    Part 2. Putting hided key into project.

    Declaring public serializable string variable:

    Code (CSharp):
    1. public class Tester : MonoBehaviour
    2. {
    3.     public string encodedKey;
    4.     // ...
    And putting our hided key eU0UQlFXRlRAFF9UTQ== in the inspector:
    http://i.imgur.com/fsRi843.png

    Part 3. Using hided key.

    Code (CSharp):
    1. public class Tester : MonoBehaviour
    2. {
    3.     public string encodedKey;
    4.     private ObscuredString key = "";
    5.  
    6.     private void Awake()
    7.     {
    8.         string encryptedKey = Encoding.UTF8.GetString(Convert.FromBase64String(encodedKey));
    9.         key.SetEncrypted(encryptedKey);
    10.  
    11.         // My secret key
    12.         Debug.Log(key);
    13.     }
    14. }
    Thus you'll make static key deobfuscation not so easy.

    Another, easier way:
    Just decalre public ObscuredString and set your key in inspector. Thus it will not be visible in code, but still could be restored as is from scene file (if hacker knows how to deal with it - i.e. he need to know how Unity stores serialized values in scene at least).
     
  32. mog-mog-mog

    mog-mog-mog

    Joined:
    Feb 12, 2014
    Posts:
    266
    Thanks. This is great support, super quick response and highly detailed answer. I've decided to go via Part-1-2-3 for my sensitive keys. For partial sensitive keys like SKU, I 'll go via simple ObscuredString solution setting via inspector.

    Once again, thank you for the great plugin.
     
  33. phoenixrising

    phoenixrising

    Joined:
    Aug 9, 2013
    Posts:
    57
    First, Thanks for making this!!!

    Great job.

    I was wondering can I / how can I make an Obscured Enum ?
     
  34. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @phoenixrising!
    Thanks and I'm afraid I don't know how to make obscured Enum ATM. never had such need before and you're first who asks about it %)
    Could you please give me a bit more details about your target you wish to achieve using obscured enums?
     
  35. phoenixrising

    phoenixrising

    Joined:
    Aug 9, 2013
    Posts:
    57
    well, I have an EventID which is an int.

    But in code I want it to be an enum so that I can program it easier and see it.

    Then I will obfuscate it for release (Source Code Obfuscation) so you cannot tell what the events are in the source code.

    And then it will make it a little harder to figure out how to add an event which increases experience points.

    Does this make sense?

    And then if the EventID is Anti Cheat obfuscated int, they will not be able to figure out what the events are that trigger the behaviors etc
     
  36. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    ACT obscured types are intended to use against memory search hacks - to prevent cheaters from changing sensitive values in memory - like money, speed, etc.

    I guess you're talking about another kind of protection though, intended to harden source code analysis. In such case ACT can't offer something ATM, but I have plans to integrate IL bytecode obfuscation in far (very far) update, somewhere at Unity 5.x cycle.

    So, again, Obscured* (except the ObscuredPrefs) should be used to prevent variables in memory hacking in first place.
     
  37. Moradom

    Moradom

    Joined:
    Oct 10, 2011
    Posts:
    33
    Hello Dmitriy,

    I have a few questions regarding ObscuredPrefs. Brief description on the setup, I am using device lock with a device lock level of strict. I have also registered onAlterationDetected and onPossibleForeignSavesDetected. When the game starts for the first time it will generate all the saved data. So far so good.

    1. I am testing out this functionality and I cannot get onAlterationDetected to fire. I will go into the Plist and modify variables (editor is closed). Then when the game checks to see if any modifications to the saved data have occurred (I do this by reading the saved data at startup. In your documentation you say that this callback will be called upon reading some altered data) it will never fire. But what is really confusing is that the Plist will be modified and the changed variable will return back to the original value after the check and I am not doing this in code.

    2. The only time I can get onPossibleForeignSavesDetected to fire is by manually changing the device ID then re-running my checker (this approach includes all entries) on my Plist that was generated with the original device ID. I believe this is working as intended, but when when I manually change an entry in the Plist to have a different device ID then the rest of the entries this is not called.

    I have the latest release of ACT that in in the Unity store.

    Could you please explain if I am not understanding the intent of these checks. Also can you give me a brief example how I can make each of these callbacks fire with my Plist?

    Great tool btw!

    Cheers
     
    Last edited: Sep 8, 2014
  38. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey @Moradom!
    First of all, thanks for your deatailed questions. I'll try to answer them.

    1. Are you sure you do not write values before reading them at the start of your application? It really looks like so - you'll not get onAlteration callback and you'll get your original values in plist if you'll write values before reading.

    If you're sure you're not doing it - could I have project with repeatable case from you please? It would really help to find out root of this issue since I did tried to repeat it, but I got onAlteration called every time I tried to change anything in my saves (on Win, in registry though).

    2. Same thing here, I can't reproduce it in my environment - tried to change trail of the one saved pref and got onPossibleForeign call with following read as expected.
    Could you please provide project with repeatable case to let me investigate it further?

    Thanks for your questions once again!
     
  39. Moradom

    Moradom

    Joined:
    Oct 10, 2011
    Posts:
    33
    Hi Dmitriy,

    Thanks for the quick reply.

    I am sure I am not writing values. Though there could be something with the editor that I am not aware of.

    To ensure the editor is not doing something under the hood I close it out, modify the Plist and start the game up. I will not get the callbacks. I can send you my data script to see what I am doing. How would you like to me send this?

    I am working in a MAC environment.

    Thanks!
     
  40. Moradom

    Moradom

    Joined:
    Oct 10, 2011
    Posts:
    33
    One more thing I thought I would share.

    After trying many other things, I am very baffled on what I am seeing. I disabled my whole game object that deals with checking and writing saved data (other than setting the crypto key). I know for a fact that I am not writing or reconstruction the Plist.

    I close the editor and I literally remove half my Plist of saved game data. Open the up editor and start my game. The code that checks for data integrity is disabled so it goes on to load the first real scene. My whole Plist is reconstructed again from the last point the game was saved.

    This is looking like Unity is storing its own version of the Plist and not the one located at (For Mac) ~/Library/Preferences/... Like some type of Meta data associated with the project. The file located at ~/Library/Preferences/... is just a dumping place for unity to place the preferences by not really used by the editor itself. This is the only thing that makes sense to me. Its like there are two Plist, one used by the editor and the other stored as stated by Unity's documentation.
     
  41. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Oh, it sounds weird... Looks like it's not related to my toolkit.
    Did you tried to repeat this in standalone build, outside of the editor?
     
  42. Moradom

    Moradom

    Joined:
    Oct 10, 2011
    Posts:
    33
    I would agree, it is hard to try this on a standalone platform. This is for an android system and I would have to root the phone to be able to attempt this. Have you ever seen this on a MAC system before?
     
  43. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    No, I usually work on Win, and never had such issues on Mac =\
     
  44. Moradom

    Moradom

    Joined:
    Oct 10, 2011
    Posts:
    33
  45. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Nice, thanks for clearing it out.
     
  46. Moradom

    Moradom

    Joined:
    Oct 10, 2011
    Posts:
    33
    Hi Dmitriy

    I don't mean to spam your thread, just want to say that everything I am using ACT for is working great. Didn't realize how Mac changed Plist editing. Again thanks for the quick support and making a great plugin.
     
  47. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Sure, no worries, you're welcome! :)
     
  48. tr1stan

    tr1stan

    Joined:
    Jan 23, 2009
    Posts:
    150
    Does current version 1.3.2.1 compatible with iOS8?
     
  49. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @tr1stan, it should be fine, but I had no chance to test it on iOS8 device so far. Though I'd glad to know if it works fine, if someone tried to use ACT there.
     
  50. Cybertiger

    Cybertiger

    Joined:
    Dec 19, 2013
    Posts:
    35
    Hi Dmitriy,
    I have Unity 4.5.5 Pro and your latest ACT (as of writing 1.3.2.1) on a MAC Pro machine.
    I defined 5 Public ObscuredString types, but it seems they are using up a lot of memory?
    Basically i created a string called:
    public level_01_data = "1 3200 120 2000 3000 6000 1 1 0" which holds all my level data.
    Everytime i create a new public ObscuredString i can see a increase of about 50MB in memory.
    Is there a memory problem somewhere or am i using your tool wrong?

    Many thanks in advance