Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

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,932
    I'm glad to let you guys know about new update! First of all, let me remind you about new introduction videos I made for all current features. I'm going to add new tutorials and examples to that playlist, so feel free to subscribe for updates. And here is new overview video:


    Regarding the ACT update:

    I added full PlayMaker support for ObscuredPrefs and SpeedHackDetector (in experimental state ATM since I'm not a PlayMaker user and have no feedback on my ACT integration efforts yet).

    Moreover, this update introduces some bugfixes, new features and new behaviour for all detectors - you have more options now on how to setup them in scene and they should live through scenes better now (even if you have detectors in different scenes which load each other).

    I'd suggest to remove previous version before updating.

    See full changelist below.

    Anti-Cheat Toolkit 1.3.4
    – added ObscuredPrefs actions for Play Maker (thanks kreischweide)
    – added SpeedHackDetected action for Play Maker (thanks kreischweide)
    – added Vector2, Quaternion, Color support to the ObscuredPrefs
    – detectors keepAlive behavior fixed and improved
    – new detectors prefab
    – increased detectors placement flexibility: you may put all detectors at one GameObject now
    – all detectors will be added to the single Game Object when instantiating from code
    – detectors Instance property reworked (can be null now)
    – fixed ObscuredCheatingDetector values were not tunable in inspector
    – fixed iPhone.vendorIdentifier error on Unity 5 iOS target platform (thanks Mike Messer)
    – obscured types now implement IFormattable for better compatibility
    – added more tooltips for detectors
    – added troubleshooting section to the readme
    – few fixes and additions in readme & API docs
    – minor refactoring in ObscuredPrefs
     
    Last edited: Dec 16, 2014
    Keitaro3660 likes this.
  2. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Glad to let you know 1.3.5 is out!

    This update has complete Opsive Behavior Designer integration (BD author support was brilliant!), new examples for PlayMaker and few other improvements and fixes!

    Please, note ACT abbreviation changed to ACTk (feel free to use #ACTk hashtag in twitter to let me easily find your tweets about plugin).

    Full changelist:
    - Anti-Cheat Toolkit now fully supports Opsive Behavior Designer, see readme for details (thanks Justin Mosiman!)
    - added new ObscuredPrefsSetNewCryptoKey Action for PlayMaker
    - added DetectorsExample scene into the PlayMaker package with SpeedHackDetector usage example
    - added ObscuredPrefsExample scene into the PlayMaker package with simple ObscuredPrefs usage example
    - fixed obscured vars initialization via SetEncrypted()
    - serialization support added to: ObscuredQuaternion, ObscuredVector3 & ObscuredVector2
    - rendundant alteration callback logic removed from ObscuredPrefs
    - removed deprecated code from ObscuredQuaternion, ObscuredVector3 & ObscuredVector2
    - plugin abbreviation changed from ACT to ACTk
    - minor fixes
     
  3. CherryPickMikko

    CherryPickMikko

    Joined:
    Nov 18, 2014
    Posts:
    1
    Hello,
    Good job on the toolkit!

    I would like to ask what would be the best way to switch from PlayerPrefs to ObscuredPrefs (used for things like highscore) in a game that is already live. I don't want to reset scores and progress for active players.

    Is it enough to rewrite PlayerPrefs to ObscuredPrefs during first launch of updated game?
    Is there something I should keep in mind to avoid any possible problems?

    Thanks for an answer.
     
  4. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey, @CherryPickMikko!
    Just change PlayerPrefs to ObscuredPrefs - ObscuredPrefs should convert old PlayerPrefs values on next read automatically.

    Example:
    1. You have your game with, let say, such code:
    var scores = PlayerPrefs.GetInt("scores");
    And you have raw "scores" value in your PlayerPrefs.

    2. Now you wish to move scores to the ObscuredPrefs. You just write:
    var scores = ObscuredPrefs.GetInt("scores");

    It will read your regular raw "scores", encrypt and save it as new ObscuredPrefs value and delete old unencrypted "scores".

    Please, let me know if you still have any further questions.
     
  5. jonkuze

    jonkuze

    Joined:
    Aug 19, 2012
    Posts:
    1,712
    Hello @Dmitriy Yukhanov, how well would you say this works for a WebPlayer Game? What about Upcoming WebGL? I need a good anti-cheat tool for my upcoming title which will be 100% Browser-based.
     
  6. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey, @Kuroato!
    All ACTk features should work fine in WebPlayer builds.
    I'm also already filled few WebGL-related bugs and QA team managed to reproduce them, so I hope it will work in WebGL after fixes as well (except the InjectionDetector since WebGL has no managed code assemblies).
     
    jonkuze likes this.
  7. jonkuze

    jonkuze

    Joined:
    Aug 19, 2012
    Posts:
    1,712
  8. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Yeah, answered there, ACTk is not really for bytecode obfuscation purposes for now, thanks for your recommendation anyway =)
     
  9. Masashi-Wada

    Masashi-Wada

    Joined:
    Jul 6, 2010
    Posts:
    90
    Hi,

    AntiCheatToolkit is using SystemInfo.deviceUniqueIdentifier on Android.
    However, it requires READ_PHONE_STATE permission and Unity gives it automatically.
    I do not use ObscuredPref and this permission is not wanted to be required of my application.
    Should I delete ObscuredPref.cs to remove this code safely?
    It will be the best hope if supported by you.

    i use unity4.5.5
     
  10. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey, @Masashi Wada!
    Just comment out the 846 line with SystemInfo.deviceUniqueIdentifier in the ObscuredPrefs.cs file and you should be fine.
     
  11. MatthewH

    MatthewH

    Joined:
    Aug 22, 2014
    Posts:
    4
    Hey @Dmitriy Yukhanov! GREAT plugin! I use it all the time! However, I'm encountering one issue. I want to keep a health obscured, but I need to access this variable from other scripts; but as you can expect it's the obscured valued. Is there a way I can access this value without it being obscured?
     
  12. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey, @MatthewH!
    If you're talking about ObscuredInt - just access it from any other scripts as usual. ObscuredInt <-> int casts implicitly.
     
  13. MatthewH

    MatthewH

    Joined:
    Aug 22, 2014
    Posts:
    4
    Thank you for the quick response @Dmitriy Yukhanov!
    Well I access it like...
    Code (csharp):
    1. GameObject.Find("Game").GetComponent<Game>().Health;
    Could you give me an example of how I should do it instead? Because the way I'm doing it is coming back as an ObscuredInt.
     
  14. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    If implicit conversion doesn't kick in, just cast it explicitly then:

    (int)(GameObject.Find("Game").GetComponent<Game>().Health);
     
  15. MatthewH

    MatthewH

    Joined:
    Aug 22, 2014
    Posts:
    4
    Awesome! That works! Thank you VERY much!

    Any ETA on the code obfuscation for ACTk? That would be another very helpful feature! :)
     
  16. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    No, I'm waiting for this first:
    http://feedback.unity3d.com/suggestions/access-to-final-assemblies-before-they-put-in-build

    And then I'm going to implement IntegrityChecker and perhaps simple bytecode obfuscation.
    Anyway, I'm not going to implement any robust obfuscation solution here so far, as there are lot of other great players on this field, like Eazfuscator. I bet its author is waiting for the same thing as me to seamlessly integrate it to the build process.
     
  17. MatthewH

    MatthewH

    Joined:
    Aug 22, 2014
    Posts:
    4
    Awesome! I was looking at others, but as an indie developer with a minimum wage job...that kind of extra money is hard to come by sometimes! :p
     
  18. Vapor

    Vapor

    Joined:
    Dec 28, 2014
    Posts:
    1
    Pardon me for not reading through all 7 pages but here is what we are looking for :
    - ACT taking random user screenshots for visual hacks (walling, aimbots etc...) with settings. For instance, take a screenshot from all users on server every 8 minutes?
    - Output of screenshots to custom url in .png format for review
    - Assigning each registered user with a custom "Guid" for easy identification purposes

    Is this possible
    Side note: This is going to be for a PC fps game only.
    Thanks Dmitriy
     
  19. Cybertiger

    Cybertiger

    Joined:
    Dec 19, 2013
    Posts:
    36
    Hello Dmitry,
    I just ran in an issue.
    I wanted to compile the game and it gave me an error stating that it can't find the namespace "UnityEditor" on a couple of your scripts.
    It is weird because "UnityEditor" is in most of my scripts as well and it doesn't complain about it.
    I am using your latest Plugin with Unity 4.5.5.
    Every had this issue?
    I guess i must be doing something wrong or everyone else would also have this problem.
    Many thanks in advance for your help

    Ps.: here is a one of the error messages:
    Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ActPostprocessor.cs(16,7): error CS0246: The type or namespace name `UnityEditor' could not be found. Are you missing a using directive or an assembly reference?
     
    MrLucid72 likes this.
  20. mog-mog-mog

    mog-mog-mog

    Joined:
    Feb 12, 2014
    Posts:
    266
    Everytime I start the game, it gives me following warning:
    "
    [ACT] SpeedHackDetector: System DateTime change detected!
    UnityEngine.Debug:LogWarning(Object)
    CodeStage.AntiCheat.Detectors.SpeedHackDetector:Update() (at Assets/CodeStage/AntiCheatToolkit/Scripts/Detectors/SpeedHackDetector.cs:238)"


    Not sure what am supposed to do?
     
  21. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Oh, looks like somthing happened with notifications again, sorry for my late reply guys.

    @Vapor
    It's partially possible, thanks for your question. I added this to my TODO. I see it like this: ACTk will be able to take screenshots and send them with POST request to the specified url with specified arguments. So you'll be able to pass user ID or user ID based guid, with any other arguments (timestamp for example) to your php script along with screenshot itself.

    @Cybertiger
    Looks really strange, I never had such reports from customers. Could you please send your project for inspection to my support email (it can be found in readme)?

    @lilboylost
    Please update to the latest version, it should be fixed there. If this will repeat after update, please let me know.
     
  22. Cybertiger

    Cybertiger

    Joined:
    Dec 19, 2013
    Posts:
    36
  23. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    @Cybertiger it shouldn't happen with default files placement (Assets/CodeStage/...). Are you sure you didn't move entire CodeStage folder to the Plugins folder?

    Looks like Unity tries to include Editor files into your build which shouldn't happen if you have plugin in its default location...
     
  24. renjian21

    renjian21

    Joined:
    Sep 2, 2014
    Posts:
    5
    Hi there, first of all, thanks for the great plugin! We have purchased ACT and it really helps.

    I just would like to consult one question about Speed Hack Detector - can it use frame delta time to detect the hack? I'm asking this because we're facing one speed hacking tool which will not be detected by ACT.

    If we activate the hacking tool before SpeedHackDetector.StartDetection, ACT will report nothing...
    if we activate the hacking tool before SpeedHackDetector.StartDetection, ACT will report hack detected.

    Does that mean we have to start the detection as soon as the game is launched? (in our current design, the detection will only be started when a actual game race is started, and detection not used while player still on UI) we're doing a multiplayer racing game and speed hack is very sensitive.
     
  25. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey, @renjian21!
    I tried to measure frame delta but it remains unchanged with Cheat Engine's speedhack (FPS doesn't change).
    SpeedHackDetector should react on speedhack even if it started after applying speedhack to the game. It measures difference between in-game and system timers, thus it should react on applied speed hack anyway.

    Could you please give me more details about your case to let me repeat it (speedhack tool name would help a lot)?
     
  26. BD54

    BD54

    Joined:
    Feb 16, 2014
    Posts:
    3
    Hey all

    Upon reading the readme.pdf of this neat asset I stumbled upon the text that states I should change the cryptokey of the obscured types. Could someone shed some light on the following questions?

    If I set/change the cryptokey, does it need to change at every startup of the game? Also wouldn't it be (security-wise) a bad idea to have the cryptokey in code? (as unity files can sometimes be decompiled almost back to its source).
     
  27. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Where else would you store it?
     
  28. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey, @monserboy!
    It's all up to you. You can change key at every startup, on every new scene or change it only once at all. It depends on your targets.
    Just remember if you'll use let say ObscuredInt.Encrypt() without specifying key or GetEncrypted() - you'll need to use current key to decrypt it back.

    Yeah, it's a bad idea, I'd suggest to hide key from code using serialization: just declare public var for your key on some game object to expose it to the editor and set key value from there. It still can be revealed by cheaters familiar with Unity serialization - they'll decompile unity build and open scene in Unity. But it requires a lot more effort comparing to simple decompilation of your code.

    You even can declare public var with initialization to troll cheater:
    public int obscuredKey = 646212;
    and change it in editor to another value.

    Best way to hide key from code - store it on server and query it using secure connection. But not every game has own server.
     
    BD54 likes this.
  29. renjian21

    renjian21

    Joined:
    Sep 2, 2014
    Posts:
    5
    @Dmitriy Yukhanov Thanks for helping. It is a famous tool (and ease-of-use) in China. The link is http://www.sbtools.org/thread-2566-1-1.html. I'm sorry about that it only has a Chinese version. Please click "SBGameHacker.apk" to download it. After the hacking tool is launched, by default, it's at its memory editing function. Just glide its center panel to the left then it will switch to speed hacking mode. In speed hacking mode, there is a checkbox named "强制加速" which is used to activate the speed.
     
  30. renjian21

    renjian21

    Joined:
    Sep 2, 2014
    Posts:
    5
    Btw, is there any online post about the game speed cheating? Just very interested to learn how those cheat enginee works.
     
  31. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    I see now, does this tool works on root level? I believe I wrote in this thread before ACTk's speed hack detector won't work correctly with such root-level tools since they are able to speed up system time (only for selected app) as well.
    But I have plans to implement reading reliable time from additional sources (like time servers) in future ACTk versions.

    Feel free to watch this video for an example.
     
  32. renjian21

    renjian21

    Joined:
    Sep 2, 2014
    Posts:
    5
    Yes it is designed to work on root level. Temporarily we have implemented some time detection on server to detect the hack.

    The way we did was -
    client is reporting its position and time (Time.time) 5 times a second.

    For each client report, calculate client time elapsed.

    And on server side, also calculate server time elapsed (based on the time when the client update is received)

    Then compare the two values, considering the round trip time between client and server. If the clientTimeElapsed - (serverTimeElapsed + roundTripTime) > threshold, then catch it as cheating (allowing 3 false positives, learning from ACT code ;-)

    How do you think about that?
     
    Last edited: Jan 23, 2015
  33. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Yes, this is a right way to go for sure. I'd implement something similar in my server-based game (if I had one).
     
  34. fishg

    fishg

    Joined:
    Jul 25, 2014
    Posts:
    90
    Hi,
    I found a bug on Unity 4.6.2 when I use IL2CPP backend to build an iOS version running on iPhone 5,this expression incorrect:
    public void AddKillScore(float kscore){
    //bug is killScore is always 0,killScore is type of ObscuredFloat
    killScore += kscore;
    }
     
  35. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    @fishg
    Thanks, will take a look.
     
  36. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    @fishg I managed to reproduce this issue. And I'm afraid it's on the IL2CPP side (mono build works perfectly fine). I'll fill a bug report and will keep any news related to this issue on this forum.

    InjectionDetector has some issues with IL2CPP as well, I'm looking into it to fill a detailed bug report, it's a IL2CPP side issue as well (Mono build works fine).
     
  37. fishg

    fishg

    Joined:
    Jul 25, 2014
    Posts:
    90
  38. afterbeta

    afterbeta

    Joined:
    Feb 20, 2013
    Posts:
    10
    Hi Dmitriy,
    I'm new to this tool. Do I need to call ObscuredCheatingDetector.StartDetection(callback) in every scene? In your example, the callback is defined in a MonoBehaviour object for a specific scene. If we change to another scene, that object is gone. And the callback won't be valid. I haven't seen this discussion in the readme file. Thank you.
     
  39. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey @afterbeta!
    All detectors are placed onto the Anti-Cheat Toolkit Detectors GameObject by default which will survive new scene load if you have Keep Alive option enabled at least in one of detectors (enabled by default). So detector itself will keep working through the whole game by default.
    So I'd suggest to add script where you're starting detector and listening to the callback to the same object to keep it alive through the whole game as well.
    Or you may use DontDestroyOnLoad for your game object with callback listener as well if it's more preferable.
     
  40. afterbeta

    afterbeta

    Joined:
    Feb 20, 2013
    Posts:
    10
    Thanks for the quick reply!
    I just want to point out that when I went to another scene and came back to the old one, there were two detector GameObjects in the scene. What I did is creating an obscured cheating detector object in the starting scene, and add my own little script to it (as you suggested). I'd think when I came back to the starting scene, the detector GameObject should ideally be maintained as a singleton. I'm guessing in your ActDetectorBase.Init(), Destroy(this) is used instead of Destroy(gameObject). So only the detector script component got destroyed. Please correct me if this is the intended behavior. Thanks again.
     
  41. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey, yeah, this is a correct behaviour. Well, sort of =)
    When detector destroys itself, it destroys only own Component and then it checks if hosting GameObject has any other scripts on it and removes GameObject if it has no any other scripts.

    If you have detector's KeepAlive enabled, your initial detector should not self-destroy at all. How did you created an object for obscured cheating detector? Did you used Create Other > CodeStage > Anti Cheat Toolkit -> Obscured Cheating Detector menu or you did created it from code?

    I just wish to try reproduce it myself to let you know if it's an actual bug or something else.
     
  42. afterbeta

    afterbeta

    Joined:
    Feb 20, 2013
    Posts:
    10
    I see. It seems my issue is due to the fact I attached my own script to the detector object. Removing my script solved the problem. By the way, I only use the memory cheating detector and KeepAlive wasn't mentioned for this detector in your readme file. But I get what it does. Thanks!
     
  43. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Yeah, I'll add KeepAlive and AutoDispose descriptions to the ObscuredCheatingDetector section of the readme, thanks.
    And I got it now, you're right, second detector's game object will be there on return to the first scene if it has any additional scripts. This happens because when we come back to first scene borrowing game object with KeepAlive detectors, detectors in loaded scene will try to self-destroy. And since they destroy only their components (to let you easily place detectors on any other objects) and destroy game object only when it's empty, game object remains in scene since it has another script attached to it.

    So it was my bad when I suggested you to place your script right to the game object with detectors. It will work only when you have same game object in every scene and you have KeepAlive disabled. In such case it will re-start detectors and re-assign callbacks in every new scene. But it's not resource-wise to do it, so you can use KeepAlive detectors on one game object and your callback subscription script on another one, but you'll need to control your callback subscription object yourself.

    As a good compromise I could add complete destroy of the Anti-Cheat Toolkit Detectors game object if it has no any other detectors on it regardless of any other scripts and child objects attached to it.
    Thus you'll be able to attach any scripts to this object and don't afraid they'll lead to this double-game object issue.
     
  44. afterbeta

    afterbeta

    Joined:
    Feb 20, 2013
    Posts:
    10
    I support anything that can make implementation of callbacks easier. Just make sure the added option won't get too complicated to explain to users. :) Again thanks for the excellent support!
     
  45. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    To all: I was able to nail down WebGL and IL2CPP issue up to this: explicit StructLayout just don't work there. Bug report sent, hope to see it fixed in near future. I believe it's a last step from full compatibility with WebGL and IL2CPP iOS.
     
  46. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Good news!
    IL2CPP bug is already fixed and it's going to be released in 4.6 patch release 1 or 2 (https://twitter.com/lucasmeijer/status/565457870305890304).
    Regarding 5.0 - it most likely will be released in 5.0.p patch release (https://twitter.com/lucasmeijer/status/565457973091520512).

    For now, I'll release an update with temporary workaround using BitConverter (it will work slower comparing to the StructLayout approach) and will revert back to StructLayout in future (when I'll update project to 4.6).
    It's going to be 1.4.x update (1.4.0 already went for review) and I'll keep you posted.

    I'll make temporary versions of bugged classes with workaround and will send them on your requests.

    Reminder: this bug touches only ObscuredFloat, ObscuredDouble and ObscuredDecimal types.
     
    Last edited: Feb 11, 2015
  47. el_saq

    el_saq

    Joined:
    Feb 6, 2015
    Posts:
    7
    Hey Dmitriy, great job! I have purchased your plugin minutes ago, it´s really easy to use, I only have one error that the console throws, look:

    Internal compiler error. See the console log for more information. output was:
    Unhandled Exception: Mono.CSharp.InternalErrorException: Assets/CodeStage/AntiCheatToolkit/Editor/Scripts/ActEditorGlobalStuff.cs(9,24): CodeStage.AntiCheat.Editor.ActEditorGlobalStuff ---> System.TypeInitializationException: An exception was thrown by the type initializer for Mono.CSharp.AttributeTester ---> System.NullReferenceException: Object reference not set to an instance of an object

    Maybe I have done something wrong? I only changed my important Flotas to ObscuredFloats, and the same with PlayerPrefs.

    I´m using Unity 4.6.2 and your asset store version (1.3.5).

    Thanks for your time!

    Update:

    I have restarted Unity and the error disapears, I don´t know why, maybe was an error of my PC.

    Thanks for your great job!
     
    Last edited: Feb 11, 2015
  48. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    @el_saq thanks for the heads up, I did saw something similar earlier but I couldn't repeat it myself, looks like a rare Unity or mono bug.
     
    Last edited: Feb 11, 2015
  49. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    @fishg please let me know if you need IL2CPP fix asap and you're not going to wait for Unity 4.6.2 patches. I'll send you modified classes with workaround.
     
  50. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,932
    Hey everyone!
    Glad to let you know Anti-Cheat Toolkit 1.4.0.1 is live!
    This update highlight: completely re-written ObscuredPrefs internals. It became faster, more accurate, and more secure, woot!
    And don't worry - it should migrate from previous ObscuredPrefs version automatically.

    Full changelist:

    1.4.0.1

    – fixed ObscuredPrefs.SetColor for WebPlayer

    1.4.0
    – massive ObscuredPrefs update:
    * uint support added
    * Rect support added
    * overall performance and memory usage improvements
    * values are locked to keys now to prevent value swapping
    * all service data in final values is hidden now
    * hashing algorithm replaced with more secure keeping the same performance
    * SetColor/GetColor optimizations
    * Float accuracy increased
    * Double accuracy increased
    * ByteArray support fixed (no more extra length after load)
    * PREVENT_READ_PHONE_STATE define introduced to let you remove Android permission if you don’t use lockToDevice
    * legacy ObscuredPlayerPrefs support removed (use previous ACTk version to read them)
    * ForceDeviceID() method replaced with DeviceID property (now you can retrieve current device ID as well)
    * format improvements allowing to easily change it with backwards compatibility
    * refactorings
    – ObscuredString.EncryptDecrypt() optimization (affects all Get/Set methods in ObscuredPrefs)
    – disabling and enabling started detectors now should pause and resume them
    – Anti-Cheat Toolkit Detectors object will self-destroy now ignoring attached scripts and nested objects
    – fixed disabled detectors behavior on StartDetection()
    – fixed issues with casting obscured vars from objects in the Behavior Designer package
    – fixes in readme
    – fixes in docs
    – other minor fixes

    Have fun! And please let me know if you'll have any issues with new ObscuredPrefs - it was lot of changes and something could get out of my sight and tests.