Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Anti-Cheat Toolkit: stop cheaters easily!

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

  1. Timmy-Hsu

    Timmy-Hsu

    Joined:
    Aug 27, 2015
    Posts:
    51
    Hi,

    Can InjectionDetector detect APK modifications that use APKTool to unpack the APK and repackage it with a non-original Keystore or repackage it after editing same files(xml or json or so or dll)?

    Thank you.
     
  2. haeggongs

    haeggongs

    Joined:
    Jul 19, 2016
    Posts:
    5
    Unity 2021.3.12f1
    Target Platform : Android

    upload_2023-5-24_15-22-17.png

    upload_2023-5-24_15-22-33.png


    upload_2023-5-24_15-23-16.png
     
  3. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Greetings @Timmi-Hsu,

    Injection Detector does detects only managed assembles injected at runtime.

    To detect apk modifications you can use the CodeHashGenerator.
     
  4. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Thanks for the extra info @haeggongs,

    I've sent a DM with few more questions about your case.
     
  5. haeggongs

    haeggongs

    Joined:
    Jul 19, 2016
    Posts:
    5
    Assets\Code\JsonDotNet\Source\Linq\JValue.cs(341,14): warning CS0436: The type 'JTokenType' in 'D:/Assets/Code/JsonDotNet/Source/Linq/JTokenType.cs' conflicts with the imported type 'JTokenType' in 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. Using the type defined in 'D:\Project\Assets/Code/JsonDotNet/Source/Linq/JTokenType.cs'.

    Assets\Code\JsonDotNet\Source\Linq\JTokenWriter.cs(368,23): warning CS0436: The type 'JsonToken' in 'D:\Project\Assets/Code/JsonDotNet/Source/JsonToken.cs' conflicts with the imported type 'JsonToken' in 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. Using the type defined in 'D:\Project\Assets/Code/JsonDotNet/Source/JsonToken.cs'.


    ...
    ...

    Many warning messages appear.
     
  6. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi @haeggongs ,

    Looks like you have JsonDotNet library added to your project in the Assets\Code\JsonDotNet folder while having it added somewhere else, for example, you may have added the Newtonsoft Json Unity Package which causes these warnings to appear. You need to keep only one Newtonsoft Json.NET library in your project to avoid this.
    I'd suggest removing the Assets\Code\JsonDotNet and keeping package version only,
     
  7. RandomCharacters

    RandomCharacters

    Joined:
    Nov 29, 2012
    Posts:
    262
    I just upgraded to latest version. Is the upgrade as easy as deleting the old folders and installing the new package? By that I mean will it recognize it and work?
     
  8. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi @RandomCharacters, yes it should work like this. If you update from very old version, it's expected to have some compilation errors due to APIs depreciation.

    Please let me know if you'll have any problems updating.
     
  9. RandomCharacters

    RandomCharacters

    Joined:
    Nov 29, 2012
    Posts:
    262
    I just upgraded and am getting a ton of errors. Where ever I reference obsuredprefs it gives an error. I must have erased something that referenced it ot it changed. It's been a long time since I used this so any help would be good. Although, it could be a different plugin too.

    Did it change from
    ObscuredPrefs.
    to
    ObscuredFilePrefs.
    ?


    Assets\3-SCRIPTS\SCRIPTS-NoPlayerPrefs\AudioMixLevels.cs(40,17): error CS0103: The name 'ObscuredPrefs' does not exist in the current context


    ////////////////////////////////////////////////////////////
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Audio;
    using UnityEngine.UI;
    using CodeStage.AntiCheat.ObscuredTypes;
    ////////////////////////////////////////////////////////////
    public class AudioMixLevels : MonoBehaviour
    {
    ////////////////////////////////////////////////////////////
    //VARIABLES
    public AudioMixer masterMixer;
    public Text sfx_TEXT;
    public Text music_TEXT;
    public ObscuredFloat currentVolumeOfSfx_FLOAT;
    public ObscuredFloat currentVolumeOfMusic_FLOAT;
    public Slider sfx_Slider;
    public Slider music_Slider;
    float sfx_Linear_FLOAT;
    float music_Linear_FLOAT;
    //OBS VARIABLES

    ////////////////////////////////////////////////////////////
    void Start()
    {
    //Load componnents.
    sfx_TEXT = sfx_TEXT.GetComponent<Text>();
    music_TEXT = music_TEXT.GetComponent<Text>();
    ////////////////////////////////////////////////////////////////////////////
    //Load SFX volume from player prefs.
    if (ObscuredPrefs.HasKey("PP-" + "currentVolumeOfSfx_FLOAT")) ////ERROR
    {
    //Load from player prefs.
    currentVolumeOfSfx_FLOAT = (ObscuredPrefs.GetFloat("PP-" + "currentVolumeOfSfx_FLOAT")); //ERROR
    }
    else
    {
    //No player prefs so make volume 0 db.
    currentVolumeOfSfx_FLOAT = 0.0f;
    //Save to player prefs.
    ObscuredPrefs.SetFloat ("PP-" + "currentVolumeOfSfx_FLOAT", currentVolumeOfSfx_FLOAT); //ERROR
    ObscuredPrefs.Save(); //ERROR
    }
    /////
     
    Last edited: Jul 3, 2023
  10. RandomCharacters

    RandomCharacters

    Joined:
    Nov 29, 2012
    Posts:
    262
    1) I'm guessing that I need to add at the top:
    using CodeStage.AntiCheat.Storage;

    2)Also, what is the format for:
    if (ObscuredPrefs.HasKey("PP-" + "currentVolumeOfSfx_FLOAT"))
    and
    ObscuredPrefs.Save();

    I looked in the user manual and didn't see these (haskey and save). It gives warnings that using these lile this will be removed in the next API, so I guess I have to change over 10,000 of this in all of my projects.

    3) I see that the set and get are different now. i am assuming I have to do:
    ObscuredPrefs.Set<float>
    and
    ObscuredPrefs.Get<float>



    Before I change hundreds of scripts with thousands of changes, I just wanted to confirm.
     
    Last edited: Jul 3, 2023
  11. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi @RandomCharacters

    1. This is correct,
    ObscuredPrefs
    is now moved into the
    CodeStage.AntiCheat.Storage
    namespace.

    2. ObscuredPrefs.HasKey() will not be deprecated, it shouldn't show any warnings when you use it. Just use it as usual:
    var someKeyExists = ObscuredPrefs.HasKey("someKey");
    .

    Same for the ObscuredPrefs.Save() - it shouldn't show any warnings as API didn't change and not going to change.
    Please let me know if you still see any warnings from these specific APIs.

    3. Yes, now you can use generic Set \ Get like this:

    Code (CSharp):
    1. ObscuredPrefs.Set("someVar", myFloatVar);
    2. myFloatVar = ObscuredPrefs.Get("someVar", 0f); // will figure out type from default value
    or like this:

    Code (CSharp):
    1. ObscuredPrefs.Set("someVar", myFloatVar);
    2. myFloatVar = ObscuredPrefs.Get<float>("someVar"); // will figure out default value from specified type
    Please let me know if you have any questions.
     
  12. RandomCharacters

    RandomCharacters

    Joined:
    Nov 29, 2012
    Posts:
    262
    I am guessing this changed at some point?

    warning CS0618: 'ObscuredInt.ApplyNewCryptoKey()' is obsolete: 'This API is redundant and does not perform any actions. It will be removed in future updates.'

    void Start ()
    {
    //Apply for public/static/serialized in Start()
    lowestPageNumber_INT.ApplyNewCryptoKey();
    highestPageNumber_INT.ApplyNewCryptoKey();
    whichPageOnRightNow_INT.ApplyNewCryptoKey();

    ======================================
    and this too?

    warning CS0618: 'ObscuredInt.SetNewCryptoKey(int)' is obsolete: 'This API is redundant and does not perform any actions. It will be removed in future updates.'

    void Awake()
    {
    //Set new default. Do this only 1 time in awake then all others in start.
    ObscuredInt.SetNewCryptoKey(theBigOne_INT);
    }
    ==================================
    So, are these not needed anymore?
     
    Last edited: Jul 5, 2023
  13. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Yes, the
    ApplyNewCryptoKey()
    and
    SetNewCryptoKey()
    APIs are deprecated now.
    If you wish to force a crypto key change, please use the RandomizeCryptoKey() API instead to assign a new random crypto key to your obscured type instance.
     
  14. RandomCharacters

    RandomCharacters

    Joined:
    Nov 29, 2012
    Posts:
    262
    when you say depreciated, then what I am hearing is that I should just delete them. They are no longer needed.

    I had this script in my bootstrapper scene. I vaguely remember it was needed. So I don't need this any more? Sorry, it's been a few years.

    //////////////////////////////////////////////////////////
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    //////
    using CodeStage.AntiCheat.ObscuredTypes;
    using CodeStage.AntiCheat.Storage;
    /////
    //////////////////////////////////////////////////////////
    public class AAAAA : MonoBehaviour
    {
    //////////////////////////////////////////////////////////
    //VARIABLES
    //OBSVARIABLES
    //Set in inspector to hide.
    public ObscuredInt theBigOne_INT;

    //////////////////////////////////////////////////////////
    void Awake()
    {
    //Set new default. Do this only 1 time in awake then all others in start.
    ObscuredInt.SetNewCryptoKey(theBigOne_INT);
    }
    //////////////////////////////////////////////////////////
    }
     
  15. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Yes it's safe to just delete them.
     
  16. Leonid

    Leonid

    Joined:
    Aug 20, 2013
    Posts:
    90
    Hello!
    Which is safer - store obscured values in code or serialize them?
    And is there a way to automatically randomize the keys, or do I have to do it manually?
    Thank you!
     
  17. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi @Leonid

    I'd say it's safer to store them in code if you do protect your code with external native protectors or do at least obfuscate it and use IL2CPP. Otherwise, it's not much difference - both serialized data and non-obfuscated IL are easy to inspect and reverse-engineer.

    Keys randomization does happen automatically - each new obscured type instance has the own unique random crypto key.
    You can still manually trigger randomization and re-encrypt data using a new random key with RandomizeCryptoKey() API call. Please refer to the API docs and User Manual for more info about this API.
     
    Leonid likes this.
  18. SOL3BREAKER

    SOL3BREAKER

    Joined:
    Oct 11, 2021
    Posts:
    39
    I want to know why 2 ObscuredStrings can point to the same memory.
    Now my 2 string value start to sync, which will cause problem. Ordinary string won't cause that.

    Code (CSharp):
    1.  
    2. public ObscuredString string1;
    3. public ObscuredString string2;
    4.  
    5. public void Test()
    6. {
    7.          string1 = string2;
    8. }
    9.  
     
  19. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hey, that's because ObscuredString is an ordinary class (reference type), so it behaves like an ordinary reference type, while built-in regular string is a reference type that behaves like a value type.

    We can't overload the assignment operator in C# to emulate the unusual string as a value type behavior, so there's no way to force this behavior for an ordinary custom class without changing it to the value type (structure), which would make ObscuredString a value type, breaking some other expectations you might have from the string reference type.
     
  20. Gaben09

    Gaben09

    Joined:
    Aug 14, 2023
    Posts:
    1
    Thanks for the asset! I bought it along with Mfuscator and no cheaters in sight yet
     
    Dfnutnu, Syncline1, VfxFaul and 2 others like this.
  21. Creijstal

    Creijstal

    Joined:
    Dec 3, 2020
    Posts:
    1
    Thank you!
     
  22. sly_88

    sly_88

    Joined:
    May 8, 2018
    Posts:
    25
    I saw a way to disable the plugin via MelonLoader

    You can find the game object with the controller and disable it it means deactivating the plugin. do you have a solution to patch it?
     
  23. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi @sly_88, there is no a single controller for all ACTk tools, they all work independently.

    Anyway, please take a look at the Code obfuscation and overall code protection notes chapter in the readme to know more about how to make the code reverse-engineering and patching harder ^^

    Don't hesitate to PM me if you'll need any extra guidance on this, I'll be happy to help!
     
    sly_88 likes this.
  24. dfaeojl

    dfaeojl

    Joined:
    Sep 5, 2023
    Posts:
    4
    thanks, MelonLoader doesn't seem to be working with my game now
     
    Dfnutnu and codestage like this.
  25. sly_88

    sly_88

    Joined:
    May 8, 2018
    Posts:
    25
    codestage likes this.
  26. buzhishishi

    buzhishishi

    Joined:
    May 20, 2019
    Posts:
    1
    Hi ,Is this plugin available for unity webGL? Are there any examples?
     
  27. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi yes all features do work with WebGL except CodeHashGenerator and managed injection detector.
    Here is a live demo: https://codestage.net/uas_files/actk/demo
     
  28. SOL3BREAKER

    SOL3BREAKER

    Joined:
    Oct 11, 2021
    Posts:
    39
    Can I use SpeedHackProofTime without Time detector? I checked code, when detected speed cheating, it would use "ticks = DateTime.UtcNow.Ticks;" in timeutils.cs, is that safe? And I can get steam server time, can I use that instead?
     
  29. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Greetings, SpeedHackProofTime does require SpeedHackDetector as a dependency. Thus, you'll need to start SpeedHackDetector first before accessing SpeedHackProofTime APIs.

    Yeah, that's a straightforward way to reach system date time on pc platform without extra dependencies and online requirements, but it still can be intercepted by some hacks.

    Sure, you can use any other source if you'd like to!
    Though, there is no built-in way to feed in your time presently, so you'll need to manually do that inside timeutils class. This is actually a great idea to allow customers to feed in their custom safe ticks, and I'll implement everything needed to allow this in future updates.
     
  30. SOL3BREAKER

    SOL3BREAKER

    Joined:
    Oct 11, 2021
    Posts:
    39
    Sir, I am using IL2CPP, but I found some dll will simply be placed into the Plugins folder, so they can replace that file to unlock dlc. Do I need to use dll injection detecion? Currently I am thinking about using code hash to check that dll.

    And what if I want to support mod to modify texture or model instead of script, could I only verify scirpt and plugin files?
     
    Last edited: Dec 4, 2023
  31. SadGeminids

    SadGeminids

    Joined:
    Jul 27, 2018
    Posts:
    2
    Hi, Sir, I use 2023.2.2 version.
    It looks like everything be right on android platform.
    But when i want to build on ios platform, something wrong with these:

    "ExecutionEngineException: Attempting to call method 'CodeStage.AntiCheat.Common.KeepAliveBehaviour`1::SubsystemRegistration' for which no ahead of time (AOT) code was generated" .

    I attemped to use code in initialize function :

    var tmpWallHackDetector = CodeStage.AntiCheat.Detectors.WallHackDetector.Instance;
    var tmpTimeCheatingDetector = CodeStage.AntiCheat.Detectors.TimeCheatingDetector.Instance;
    var tmpSpeedHackDetector = CodeStage.AntiCheat.Detectors.SpeedHackDetector.Instance;

    Now, these wrong will happen on android platform. How can i avoid these wrong with generic ?
     
  32. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi @SOL3BREAKER ,
    InjectionDetector will detect foreign managed (mono) dlls injected into the app's domain, if you're building with IL2CPP, it won't work as there is no managed environment.
    In such case, I'd suggest using CodeHashGenerator to validate your build integrity.

    Yeah, both CodeHashGenerator and InjectionDetector do work with code-related binaries by default.
     
  33. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi @SadGeminids ,

    Thanks for bringing this to my attention, I'll take a look and will get back to you with any news I'll have on this problem!
     
  34. SadGeminids

    SadGeminids

    Joined:
    Jul 27, 2018
    Posts:
    2
    I attemped use different unity version and codestage version to find out the real reason.
    Using unity 2023.1.9f1:
    A. CodeStage v. 2021.0.7. Everything seems to be right.
    B. CodeStage v. 2023.3.2. AOT wrong on runtime.

    Using unity 2021.3.30f1
    A. CodeStage v. 2021.0.7. Everything seems to be right.
    B. CodeStage v. 2023.3.2. AOT wrong on compile time(Build android apk).But not wrong tips on runtime.

    I dont know if these problem is caused by compiler.

    I'm glad to communicate with you on mail about this.(crazy_lf@163.com)
     
    codestage likes this.
  35. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hey @SadGeminids

    I've tried reproducing this problem on iOS with Unity 2022.3.15 and had no luck with that.
    The example scene compiles and runs just fine on iOS 15.

    But just in case, I've wrapped all the
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
    into
    UNITY_EDITOR
    conditional, since I'm using it for the no domain reload support in Editor.

    A fix is live now. Hope it will resolve this problem for you! Otherwise, please reach out with exact reproduction steps and I'll to investigate it further.
     
  36. Avocco

    Avocco

    Joined:
    Feb 2, 2015
    Posts:
    17
    @codestage There is a bug in the latest version of the sdk, the ObscuredPrefs.HasKey function when migrating from an old version using a custom key will not return true even if the key exist because the PlayerPrefs.HasKey(EncryptKeyWithACTkV1Algorithm) is using the default value.
     
    codestage likes this.
  37. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Good find, you're totally right!

    This is now fixed and live in the store, it does use the
    cryptoKeyObsolete
    now, which you can change using the obsolete
    CryptoKey
    property.

    Thanks for reporting this defect.
     
  38. SOL3BREAKER

    SOL3BREAKER

    Joined:
    Oct 11, 2021
    Posts:
    39
    How do I protect list, if someone uses CE to add some new equip to equip list, how do I detect it.
     
  39. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Just off the top of my head: you can store list length in a separate ObscuredInt and update it every time you update the list. So when it updates without proper app action, the actual list length will not match that variable to let you detect misbehavior.
     
  40. SOL3BREAKER

    SOL3BREAKER

    Joined:
    Oct 11, 2021
    Posts:
    39
    I tested a bit, and I checked the memory of some ordinary int with cheat engine. The list only had 1 element, and the others memory nearby just refreshed all the time. When I add a new element in Editor, the previous memory address was simply released, and unity would find a new place to hold these 2 elements, it works like Array with a certain length. So if I didn't anounce the list with an initial length, I guess player may not be able to simply use CE to add new element.
     
    codestage likes this.
  41. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
  42. Colin_MacLeod

    Colin_MacLeod

    Joined:
    Feb 11, 2014
    Posts:
    319
    @codestage: Are you aware of some typos in the GUI styles in the latest version of ACTK (v2023.2.6)?

    "Seach" instead of "Search" throws up errors when using the Player prefs window.

    Code (CSharp):
    1. [ACTk] Can't find builtin style ToolbarSeachTextFieldPopup
    2. UnityEngine.Debug:LogError (object)
    3. CodeStage.AntiCheat.EditorCode.GUITools:GetBuiltinStyle (string) (at Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs:397)
    4. CodeStage.AntiCheat.EditorCode.GUITools:Init () (at Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs:260)
    5. CodeStage.AntiCheat.EditorCode.GUITools:get_Toolbar () (at Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs:160)
    6. CodeStage.AntiCheat.EditorCode.ACTkPrefsEditor:OnGUI () (at Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs:121)
    7. UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&) (at /Users/bokken/build/output/unity/unity/Modules/IMGUI/GUIUtility.cs:190)

    upload_2024-1-20_13-30-25.png
     
  43. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hey those are actual typos in Unity built-in styles till some version until they fixed them haha

    Actually, I added support for new fixed styles at ACTk 2023.2.3, please ensure you're using the latest version.

    It has such code at the
    CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs > void Init()

    Code (CSharp):
    1. toolbarSearchTextField = GetBuiltinStyle("ToolbarSeachTextField", true) ??
    2.                     GetBuiltinStyle("ToolbarSearchTextField");
    So it first tries to look for the misspelled version and uses "silent" argument true so it won't produce an error, next it looks for the fixed version and will produce an error only if it won't find both misspelled and correct versions.

    Perhaps, you're suffering from another Unity bug - cached asset store assets may not update properly, so try removing cached ACTk package at the C:\Users\YOUR_USER\AppData\Roaming\Unity\Asset Store-5.x
     
  44. Colin_MacLeod

    Colin_MacLeod

    Joined:
    Feb 11, 2014
    Posts:
    319
    Oh, that's very strange - and funny! I only downloaded and included ACTk into this project yesterday, so I'm fairly certain I'm on the latest version.
     
  45. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    That's interesting!

    If you see the latest version at the ACTk settings (open using menu Tools > Code Stage > Anti-Cheat Toolkit > Settings), could you please share the exact Unity version you're using, so I could try repro it on my end?
     
  46. Colin_MacLeod

    Colin_MacLeod

    Joined:
    Feb 11, 2014
    Posts:
    319
    Ah, you know, I think this is on me. It seems I've installed an older version.

    upload_2024-1-21_18-39-23.png

    Will try the 2023.2.6 version now - sorry for the confusion!

    FWIW, I'm running Unity 2022.3.17f1 on macOS 14.2.1 (Apple Silicon)
     
    codestage likes this.
  47. Colin_MacLeod

    Colin_MacLeod

    Joined:
    Feb 11, 2014
    Posts:
    319
    Yes, that works a charm. Sorry for the bad info!
     
    codestage likes this.
  48. Mad_Llama

    Mad_Llama

    Joined:
    Aug 18, 2013
    Posts:
    5
    Does this address something like BepInEx or Melonloader?
     
  49. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,929
    Hi @Mad_Llama ACTk doesn't resist reverse-engineering threats including such tools, so please make sure to complement it with good native protector to cover your build from non-managed injections, runtime code patching, debugging and such.

    Most bullet-proof combo is ACTk + code obfuscator of your choice + native protector of your choice. It will cover from most threats out there.
     
  50. Mad_Llama

    Mad_Llama

    Joined:
    Aug 18, 2013
    Posts:
    5
    Thanks for the quick reply! I'm new to this whole thing, could elaborate a bit on native protectors?