Android - App Tampering - Detector (Pro)
Cheating with Android apps often involves manipulating the app's package itself to gain advantages. This is a major problem for developers, as the tampering is a common problem. That's why AntiCheat introduces features that secure Android apps and detect if they have been compromised or altered in any way.
Detector
The 'AndroidPackageTamperingDetector' is used to detect different types of app or package manipulations. Based on this it calculates the possibility of cheating and notifies observers of the detected cheating.
Observed Subject
The detector observes the 'IAndroidStatus' interface sent by:
AndroidPackageSourceMonitor: Determines the installation source of the app (which app store or if side-loaded) and notifies observers.
AndroidPackageHashMonitor: Calculates the overall hash of the app and passes it to observers.
AndroidPackageFingerprintMonitor: Reads the signing fingerprint of the app and passes it to observers.
AndroidPackageLibraryMonitor: Reads the included libraries, containing the built code, of the app and passes them on to observers.
Detector Status
The detector observes the different monitor status and validates them with your expected values. For example if the installation source is allowed, or the app was signed by you. The expected values can be assigned in the 'AntiCheat-Settings', described in the next chapters. If a deviation and so cheating was detected, the detector notifies its observers with a 'AndroidCheatingDetectionStatus'. The status contains the following properties:
- PossibilityOfFalsePositive: A value indicating the possibility of a false positive when assessing threats for the implementing subject from 0.0 to 1.0.
- ThreatRating: The threat rating associated with the detected cheating, indicating the assessed level of a potential threat.
- AndroidCheatingType: The type of cheating detected on the Android device.
- MonitorFailedToRetrieveData: If the monitor notifing the detector failed to retrieve its data or an exception occurred while retrieving the data over the native interface. So no valid value was returned and no validation could be performed by the detector. Mostly the cause is that parts of the native implementation are not available on the current Android device, because an older sdk was used.
The 'AndroidCheatingType' property can take the following values:
- PACKAGE_SOURCE: The app package installation source is not from the allowed stores.
- PACKAGE_HASH: The app package hash is not the expected hash.
- PACKAGE_FINGERPRINT: The app package certificates fingerprint is not the expected fingerprint.
- PACKAGE_LIBRARY: The app package libraries contain a library that is not allowed.
Supported Platforms
The detector is only available on Android platforms.
Requirements
Requires an Android build with at least Android 4.4 (API level 19) (December 2013).
How To Use
The usage is quite simple, attach one or multiple android package monitors (if not already done) and a 'AndroidPackageTamperingDetector' to a child GameObject of the 'AntiCheat-Monitor', apply the required settings and define a reaction on cheating detection.
Add Monitor Component
The 'AndroidPackageTamperingDetector' is an aggregated detector that is used to detect if the Android package (APK/AAB) is tampered with. So it can subscribe to the following monitors:
- AndroidPackageSourceMonitor
- AndroidPackageHashMonitor
- AndroidPackageFingerprintMonitor
- AndroidPackageLibraryMonitor
Attach one or multiple of those monitors to a child GameObject of the 'AntiCheat-Monitor' where you will also attach the detector.
Add Detector Component
Manual
Add the 'AndroidPackageTamperingDetector' MonoBehavior from the 'GUPS.AntiCheat.Detector' namespace to your 'AntiCheat-Monitor' GameObject or better to a child GameObject.
Add the 'AndroidPackageTamperingDetector' as Component.
Prefab
There is also a prefab, including the detector and the monitors, which you can directly attach as a GameObject to the 'AntiCheat-Monitor'.
Add the 'Android Package Cheating Detector' prefab to the 'AntiCheat-Monitor'.
Settings
After attaching the 'AndroidPackageTamperingDetector' MonoBehavior to a GameObject, you will see the following in the inspector:
The settings of the 'AndroidPackageTamperingDetector' Component.
General Settings: Define here if the detector should be active.
Threat Rating Settings: Define here the severity of the detected cheating.
Observable Settings: Add here callbacks invoken when a cheating got detected.
Runtime
The detector will subscribe to all Android monitors found for the same GameObject or child GameObjects during the 'Start' MonoBehavior callback. These could be:
AndroidPackageSourceMonitor: Is used to find the installation source of the Android app. For example, if it was installed via the Google Play Store.
AndroidPackageHashMonitor: Calculates the hash of the entire Android app and returns it to the detector as a hex string.
AndroidPackageFingerprintMonitor: Provides the signing certificate fingerprint of the Android app and returns it to the detector as a hex string.
AndroidPackageLibraryMonitor: Reads all added libraries in the Android app and returns them to the detector as a list.
Validate Installation Source
By validating the installation source, you can check whether your app was installed by official app stores and not by third parties. Cheater often offer a manipulated app as a direct download so that users can install it directly.
Monitor
To validate the installation source you first need a 'AndroidPackageSourceMonitor'. It is used to find the installation source of the Android app. For example, if it was installed via the Google Play Store. The 'AndroidPackageTamperingDetector' subscribes to this and checks whether the source belongs to the allowed installation sources.
Project Settings
To assign the allowed installation sources, go to 'Edit -> Project settings -> GuardingPearSoftware -> AntiCheat'. Go to the 'Android - App Store - Settings' section.
In the AntiCheat Project Settings assign the allowed installation sources.
In the settings you can find the following options:
Allow all installation sources: Check to allow all package installation sources for your app. Uncheck to allow only the package installation sources in the list of allowed app stores.
Allow following sources: If not all installation sources are allowed. You can assign here a list of allowed package installation sources. If the app is installed from a source not in the list, the detector will allow you to react to it.
Allow custom sources: A list of allowed custom package installation sources for the application, if the store you wish to allow installation from is not in the list of allowed app stores. Enter here the package names. For example for the Google Play Store it is com.android.vending.
Detection
If the detected installation source is not in the allowed range of sources, the detector will detect this as cheating. To react to this detection look in the last chapter 'React On Cheating'.
Validate App Hash
Validating the entire app hash is a good way to determine whether the app has been modified in any way. Be it a different package name or changed code or other resources.
Monitor
The app hash is calculated by the 'AndroidPackageHashMonitor'. The 'AndroidPackageTamperingDetector' subscribes to this and checks whether the calculated hash matches a provided hash from a remote source.
Project Settings
To activate hash validation and assigning the remote source, go to 'Edit -> Project Settings -> GuardingPearSoftware -> AntiCheat'. Go to the 'Android - App Hash - Settings' section.
In the AntiCheat Project Settings apply the hash validation settings.
In the settings you can find the following options:
Verify app hash: Enable to verify the hash of the app with a remote source. Deactivate to not verify the app hash. After you have built your app, AntiCheat calculates the hash of the enite app (apk / aab) and displays it in the log. Store this hash somewhere on a server in the web, but accessible to your app. When the app starts, it can download the hash from the server and compares it with the hash of the app. If the hashes do not match, the app is not the original app.
Used hash algorithm: The algorithm used to generate and validate the app hash. Recommend: SHA-256.
Remote hash location: The server get endpoint to read the app hash from. The server should return the hash of the whole app (apk / aab) as string. The path can contain a placeholder '{version}' which will be replaced with the Application.version. For example: https://yourserver.com/yourapp/hash/{version} or https://yourserver.com/yourapp/hash?version={version}. Application.version returns the current version of the Application. To set the version number in Unity, go to 'Edit -> Project Settings -> Player'. This is the same as PlayerSettings.bundleVersion.
When you build your Android app, AntiCheat calculates the hash of your app and logs it in your editor console at the end of the build. Of course, you can also calculate the hash manually.
After building you app, the hash of the entire app will be displayed in the log console.
You can copy paste this hash hex string to a remote location, for example your server and make it available through a get request.
Note
The calculated hash changes with every build, even if you have not changed anything. So make sure that you return and validate the correct hash. To differ the hash for different build versions, you can use the placeholder '{version}' in your request URL. This will then be replaced by the 'Application.version' on request.
Assign your build version in the 'Edit -> Project Settings -> Player'.
Assign your build version in the Project Settings.
The remote source or server get response should only return the hex string of the app hash. For example, here is a small node.js express server script of what this could look like:
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`);
});
Detection
If the calculated local hash is not equals to the one returned from the remote source, the detector will detect this as cheating. To react to this detection look in the last chapter 'React On Cheating'.
Validate App Fingerprint
By validating your apps certificate fingerprint you can make sure the app is shipped by you and no one else.
Monitor
The app certificate fingerprint is provided by the 'AndroidPackageFingerprintMonitor'. The 'AndroidPackageTamperingDetector' subscribes to this and checks whether the provided fingerprint matches the one in the project settings.
Project Settings
To activate fingerprint validation and also set the fingerprint itself, go to 'Edit -> Project Settings -> GuardingPearSoftware -> AntiCheat'. Go to the 'Android - App Fingerprint - Settings' section.
In the AntiCheat Project Settings apply the fingerprint validation settings.
In the settings you can find the following options:
Verify app fingerprint: Enable to verify the app fingerprint. Disable to not check the app fingerprint. The fingerprint or signature of the app is a unique identifier. It is used to verify the app's identity and ensure that it is not tampered with.
Used hash algorithm: The algorithm used to generate and validate the app fingerprint. Recommend: SHA-256.
Fingerprint: The actual app fingerprint used to verify the app's identity and ensure that it is not tampered with or shipped through an unauthorized source. Enter as hex string.
The fingerprint is the public part of a certificate to validate its authenticity. A certificate is digitally applied to an app by using a private key (stored in a key store). It is created by a developer or an organization and is unique to their apps.
The key store is assigned by you through the 'Edit -> Project Settings -> Player -> Publishing Settings'.
Example: Android Project Settings Publishing Settings.
You can get the fingerprint directly from the app or from your keystore:
// 1. Open your cmd / terminal.
// 2. Go to your jdk location (for example):
cd "C:\Program Files\Java\jdk-17\bin"
// 3. Get the fingerprint from you keystore:
keytool.exe -list -v -keystore "[Project]\user.keystore"
Example: The certificate fingerprints using SHA1 and SHA256.
Enter the fingerprint (recommended at least SHA256) in the AntiCheat 'Android - App Fingerprint - Settings'. As long as you use the same key store and project key for you app, you only have to enter the fingerprint once, because it does not change.
Detection
If the fingerprint of apps certificate is not equals to the one stored in the settings, the detector will detect this as cheating. To react to this detection look in the last chapter 'React On Cheating'.
Validate App Libraries
A common cheat method in Unity Android apps is to insert custom libraries into your app instead of modifying the existing code. These libraries contain cheats that then give the player advantages.
Monitor
The apps libraries are read by the 'AndroidPackageLibraryMonitor'. The 'AndroidPackageTamperingDetector' subscribes to this and checks whether the found libraries are whitelisted or blacklisted.
Project Settings
To activate whitelisting or blacklisting of libraries, go to 'Edit -> Project Settings -> GuardingPearSoftware -> AntiCheat'. Go to the 'Android - App Library - Settings' section.
In the AntiCheat Project Settings apply the library settings.
In the settings you can find the following options:
White-/Blacklist libraries: Enable to use whitelisting and blacklisting for libraries. Disable to allow all libraries to be used in the app.
Whitelisted libraries: A list of whitelisted libraries that are allowed to be used in the application. If the application uses a library that is not in the list, you will get a notification. You can react to those notifications and decide what you want to do from there. A very common modding process is to add libraries to the application, which contain cheats.
Blacklisted libraries: A list of blacklisted libraries that are not allowed to be used in the application. If the application uses a library that is in the list, you will get a notification. You can react to those notifications and decide what you want to do from there. A very common modding process is to add libraries to the application, which contain cheats.
To find the libraries of your app, open your app with a zip-filemanager (for example 7Zip), go to the library directory inside the opened app (for example 'lib\armeabi-v7a') and enter all found libraries into the 'Android - App Library - Settings'. Enter the fullname including the extension.
Example: Libraries found in a build Android app.
Detection
If there are libraries found that are not whitelisted or are blacklisted, the detector will detect this as cheating. To react to this detection look in the last chapter 'React On Cheating'.
React On Cheating
When the monitor (data provider) and detector (data validator) are set up, you sure want to react on detected cheating.
Punisher
In general, any cheat detected is forwarded to the 'AntiCheat-Monitor', which calculates an overall threat level. Based on the threat level, you can apply punishments by using Punisher components added to a child GameObject of the 'AntiCheat-Monitor'. There are some built-in punishers that you can find here as prefabs:
The location of the built-in Punisher prefabs.
Inspector
You can set a callback in the Unity Inspector view of the detector. This callback is invoken as soon as the specific cheating is detected.
A list of callbacks invoken when cheating got detected from the detector.
Code
If you would like to write a custom listener to the detector, you can attach an observer:
// Get the detector.
var detector = AntiCheatMonitor.Instance
.GetDetector<AndroidPackageTamperingDetector>();
// Subscribe as observer and get notified on inconsistency.
detector.Subscribe(myObserver);
Also the detector has an inherited property 'PossibleCheatingDetected' which is set to true once a cheating got detected.