• Hello
Search Results for

    Show / Hide Table of Contents

    Android - App Tampering - Detector (Pro)

    Players can download an Android app, change it, and share that copy. This detector compares the running app with what you expect.

    Walkthrough: Protecting an Android build.

    Detector

    AndroidPackageTamperingDetector checks several kinds of app changes. If one fails, it tells its listeners.

    Observed subject

    It listens to IAndroidStatus from these monitors:

    • AndroidPackageSourceMonitor: which store installed the app.
    • AndroidPackageHashMonitor: a hash of the whole app file.
    • AndroidPackageFingerprintMonitor: who signed the app.
    • AndroidPackageLibraryMonitor: the code libraries packed in the app.

    Status

    The detector compares each report with your settings. On a mismatch it sends an AndroidCheatingDetectionStatus:

    public struct AndroidCheatingDetectionStatus : IAndroidCheatingDetectionStatus
    {
        // Probability that the detection is a false positive, in the range [0.0, 1.0].
        public float PossibilityOfFalsePositive { get; }
    
        // The threat rating reported with this detection.
        public uint ThreatRating { get; }
    
        // The type of cheating detected on the Android device.
        public EAndroidCheatingType AndroidCheatingType { get; }
    
        // True if the source monitor failed to retrieve its data over the native interface.
        public bool MonitorFailedToRetrieveData { get; }
    }
    
    • MonitorFailedToRetrieveData: The monitor could not read its data. That can happen on an older device. No real check ran, so the false-alarm chance is higher.

    AndroidCheatingType can be:

    public enum EAndroidCheatingType : byte
    {
        UNKNOWN = 0,             // Type could not be classified.
        PACKAGE_SOURCE = 1,      // Installation source is not from an allowed store.
        PACKAGE_HASH = 2,        // App hash does not match the expected hash.
        PACKAGE_FINGERPRINT = 3, // Signing fingerprint does not match the expected fingerprint.
        PACKAGE_LIBRARY = 4      // A native library is not allowed (whitelist/blacklist).
    }
    

    Threat rating and false positives

    • PossibilityOfFalsePositive: 0.01 on a real find. It rises to 0.75 when the monitor could not read its data.
    • ThreatRating: default 500 (recommended 500).

    Lifecycle and timing

    • In Awake it subscribes to whichever of the four monitors are on the same object. A missing monitor simply turns that one check off.
    • Each monitor report is checked against the project settings. A mismatch is reported.
    • In the Editor and in development builds, the checks run only when Verify development builds (Android_Enable_Development) is on.

    Configuration

    • Is Active (isActive, bool, default true): Turns the detector on or off.
    • Threat Rating (threatRating, uint, default 500): How much one find adds to the threat score.
    • On Cheating Detection Event (OnCheatingDetectionEvent): Functions to call when a cheat is found.

    Stores, the expected hash, the expected signature, and the library lists are set in Project Settings. See the sections below.

    Supported platforms

    Android only.

    Requirements

    Android 4.4 (API level 19) or newer.

    How to use

    Add one or more of the package monitors, and add AndroidPackageTamperingDetector as a child of the AntiCheat-Monitor. Fill in the settings. Then choose how you want to react.

    Add the monitors

    This detector can use:

    • AndroidPackageSourceMonitor
    • AndroidPackageHashMonitor
    • AndroidPackageFingerprintMonitor
    • AndroidPackageLibraryMonitor

    Put them on the same object as the detector.

    Add the detector

    Manual

    Add AndroidPackageTamperingDetector from GUPS.AntiCheat.Detector.Android. A child of the monitor is the best place.

    Add the AndroidPackageTamperingDetector component.

    Prefab

    The prefab includes the detector and the monitors.

    Add the Android Package Cheating Detector prefab to the AntiCheat-Monitor.

    Settings

    The AndroidPackageTamperingDetector settings.

    • General Settings: Turn the detector on or off.
    • Threat Rating Settings: How serious one find is.
    • Observable Settings: Functions to call when cheating is found.

    Runtime

    In Awake the detector subscribes to the package monitors on the same object:

    • Source: which store installed the app, for example Google Play.
    • Hash: the hash of the whole app, as text.
    • Fingerprint: the signature, as text.
    • Libraries: the library names in the app.

    Check the install source

    Cheaters often share an edited app as a direct download. This check allows only the stores you trust.

    Monitor

    Add AndroidPackageSourceMonitor. The detector checks that store against your allow list.

    Project settings

    Open Edit > Project Settings > GuardingPearSoftware > AntiCheat. Go to Android - App Store - Settings.

    Allowed install sources.

    • Allow all installation sources: On means every store is allowed. Off means only the list below is allowed.
    • Allow following sources: The stores you trust. A store that is not in the list is reported.
    • Allow custom sources: A store that is not in the built-in list. Enter its package name. Google Play is com.android.vending.

    If the store is not allowed, that is a cheat report. See React when a cheat is found.

    Check the app hash

    The hash shows whether the app file was changed. That includes a new package name, edited code, or other changed files.

    Monitor

    AndroidPackageHashMonitor calculates the hash. The detector compares it with a hash from your server.

    Project settings

    Open Android - App Hash - Settings.

    Hash settings.

    • Verify app hash: Turn the check on. After a build, AntiCheat prints the hash in the Editor log. Put that text on a server the app can reach. At start, the app downloads it and compares. If they differ, this is not the build you shipped.
    • Used hash algorithm: SHA-256 is the recommended choice.
    • Remote hash location: A web address that returns only the hash text. {version} is replaced with Application.version. Examples: https://yourserver.com/yourapp/hash/{version} or https://yourserver.com/yourapp/hash?version={version}. Set the version under Edit > Project Settings > Player. That is PlayerSettings.bundleVersion.

    After an Android build, the hash appears in the console. You can also calculate it yourself.

    The app hash in the console after a build.

    Copy that text to your server and return it from a GET request.

    Note

    The hash changes on every build, even when the game looks the same. Return the hash of the build you shipped. Use {version} in the address if you keep more than one build online.

    Set the version under Edit > Project Settings > Player.

    Set Application.version under Player settings.

    The server should return only the hash text. A small example:

    import express from 'express';
    
    const app = express();
    
    app.get('/hash', (req, res) => {
        if(req.query.version === '0.2') {
          res.send('00:E4:C4:13:2F:09:91:4A:B5:A0:D6:64:AC:38:FD:50:82:02:3C:45:5E:64:69:B1:F7:0E:43:04:14:1C:1A:3A');
          return;
        }
        res.send('Unknown version');
    });
    
    app.listen(4000, () => {
      console.log(`server running on port 4000`);
    });
    

    If the local hash does not match the server, that is a cheat report.

    Check the signature

    The signature shows the app was signed with your key.

    Monitor

    AndroidPackageFingerprintMonitor reads the signature. The detector compares it with the one in Project Settings.

    Project settings

    Open Android - App Fingerprint - Settings.

    Fingerprint settings.

    • Verify app fingerprint: Turn the check on.
    • Used hash algorithm: SHA-256 is the recommended choice.
    • Fingerprint: Your signature, as text.

    The signature is the public part of the certificate. You apply it with a private key in a keystore. It stays the same as long as you keep that key.

    The keystore is set under Edit > Project Settings > Player > Publishing Settings.

    The Android publishing key.

    Read the fingerprint from the keystore:

    keytool -list -v -keystore "[Project]\user.keystore"
    

    Copy the SHA-256 fingerprint into the AntiCheat settings.

    Paste at least the SHA-256 line into Android - App Fingerprint - Settings. You only do this once, as long as you keep the same keystore.

    If the app signature does not match, that is a cheat report.

    Check the libraries

    A common mod adds a new library instead of editing your code.

    Monitor

    AndroidPackageLibraryMonitor lists the libraries. The detector compares them with your allow list and block list.

    Project settings

    Open Android - App Library - Settings.

    Library allow and block lists.

    • White-/Blacklist libraries: Turn both lists on. Off means every library is allowed.
    • Whitelisted libraries: Libraries that may be in the app. Anything else is reported.
    • Blacklisted libraries: Libraries that must not be in the app.

    Open the built app in a zip tool. Look in the library folder, for example lib\armeabi-v7a\. Enter each file name with its extension.

    Libraries inside a built Android app.

    A library that is missing from the allow list, or present on the block list, is a cheat report.

    Read the detection in code

    You can also listen yourself. Cast the status to AndroidCheatingDetectionStatus to read the Android fields.

    using System;
    using GUPS.AntiCheat;
    using GUPS.AntiCheat.Core.Detector;
    using GUPS.AntiCheat.Detector.Android;
    using UnityEngine;
    
    public class AndroidPackageDetectionLogger : MonoBehaviour, IObserver<IDetectorStatus>
    {
        private void Start()
        {
            var detector = AntiCheatMonitor.Instance.GetDetector<AndroidPackageTamperingDetector>();
            detector.Subscribe(this);
        }
    
        public void OnNext(IDetectorStatus status)
        {
            if (status is AndroidCheatingDetectionStatus androidStatus)
            {
                Debug.LogWarning($"Android package tampering detected: {androidStatus.AndroidCheatingType} " +
                                 $"(threat={androidStatus.ThreatRating}, failedToRetrieve={androidStatus.MonitorFailedToRetrieveData}).");
            }
        }
    
        public void OnError(Exception error) { }
        public void OnCompleted() { }
    }
    

    React when a cheat is found

    The detector tells the AntiCheat-Monitor. The monitor adds the report to the threat score.

    Punisher. Add a punisher prefab as a child of the monitor. It runs when the score reaches its limit.

    Built-in punisher prefabs.

    Inspector. Add a function to On Cheating Detection Event. It runs when this detector finds a cheat.

    Inspector callbacks on a detector.

    Code.

    var detector = AntiCheatMonitor.Instance
          .GetDetector<AndroidPackageTamperingDetector>();
    
    detector.Subscribe(myObserver);
    

    PossibleCheatingDetected stays true after the first find.

    In This Article
    Back to top GuardingPearSoftware documentation