com.xmobitea.changx.antimod
v1.5.2
Published
Build-time checksum and runtime integrity validation for Unity Android and iOS builds.
Readme
XmobiTea AntiMod
Build-time checksum and integrity validation package for Unity Android/iOS builds.
AI Quick Contract
- Main runtime API:
await CheckSumChecker.TryValidate() - Main settings asset:
Resources/XmobiTea AntiModSettings.asset - Editor menu:
XmobiTea Tools/AntiMod/Open Settings - Requires editor generation step:
Yes - Requires post-build generation step:
Yes - Runtime validation is meaningful mainly on
AndroidandiOS - The post-build hook is registered globally, but the current generator is intended only for Android/iOS builds
- In
UNITY_EDITOR, validation always returns success - On non-Android/non-iOS player targets, runtime still loads and signature-checks the integrity payload, then falls back to the permissive editor checker instead of doing platform file checks
- Android first build can require a rebuild because
integrity.jsonis generated after the build output is produced - The local JSON file is used during editor/build workflows; runtime validation uses encoded values stored in
AntiModSettings integrityJsonFileshould currently stay asintegrity.json; changing it breaks the current post-build flow- iOS known-framework detection is currently not fail-safe: unknown names are treated as valid internally and the public result can still finish as success
Need-Based Routing
- Need the smallest setup/build entrypoint: open
AI_SETUP.md - Need to create or edit
AntiModSettings: openAI_SETUP_ANTIMOD_SETTINGS.md - Need the Android build workflow: open
AI_BUILD_ANDROID.md - Need the iOS build workflow: open
AI_BUILD_IOS.md - Need runtime bootstrap code only: open
AI_USAGE.md - Package-level guardrails
AGENTS.md
What This Package Provides
AntiModSettings: resource-backed config asset with runtime toggles, XOR keys, and encoded secret dataCheckSumChecker: runtime entry pointCheckSumData: serialized integrity payload modelCheckSumResult: validation result modelCheckSumUtils: hashing, signature, AES encode/decode helpersAntiModSettingsEditor: custom inspector for local secret input and encoded-field generationCheckSumGenerateEditor: post-build integrity generation and platform-specific follow-up
Exact Runtime Behavior
CheckSumChecker.TryValidate()
TryValidate() behaves like this:
- In
UNITY_EDITOR, it immediately returnsnew CheckSumResult(true, null). - On device, it resolves the integrity file name from
CheckSumUtils.GetOriginNameIntegrityJsonFile(). - It loads that file from
StreamingAssets. - It deserializes the JSON into
CheckSumData. - It recomputes the signature over
entriesand compares it with the stored signature. - It dispatches to:
AndroidCheckSumCheckerInternaliOSCheckSumCheckerInternal- fallback
EditorCheckSumCheckerInternalon other runtime targets
Important consequence: this package is not a generic desktop anti-tamper solution. Outside Android/iOS, it can still fail while loading the integrity file or verifying its signature, but after that it performs no platform-specific file-hash checks.
Android Runtime Validation
Android validation:
- finds installed
.apkfiles in the app install directory - detects whether the current install is
arm64orarmeabi-v7a - decrypts each stored path from
integrity.json - searches that path inside the installed APK files
- computes SHA-256 and compares it with the stored hash
If any required entry is missing or mismatched, validation fails.
iOS Runtime Validation
iOS validation:
- resolves the
.appinstall root - decrypts each stored path from
integrity.json - reads each file from the installed app bundle
- compares SHA-256 with the stored hash
- optionally validates
UnityFrameworkwheniOSCheckSumUnityFrameworkis enabled - optionally validates allowed framework names when
iOSCheckKnownFileInFrameworksis enabled
Current quirk:
the "unknown files in Frameworks" branch returns new CheckSumResult(true, "...") instead of failing. The caller only returns failed results, so that message can be discarded and the public result can finish as new CheckSumResult(true, null).
Data Sources
AntiModSettings
AntiModSettings is loaded from:
Resources/XmobiTea AntiModSettings.assetIt contains:
- iOS runtime toggles
- XOR keys used to decode runtime secrets, AES data, and known framework names
- encoded secret data used by runtime signature and AES helpers
If the asset is missing in the editor, XmobiTea Tools/AntiMod/Open Settings creates it automatically in Assets/Resources/.
If the asset is missing in a player build, runtime logs [AntiMod] missing AntiModSettings and validation cannot work correctly.
Local Editor JSON
Editor/build-only localSecretKeySettings is loaded from this file when it exists:
Assets/XmobiTea-constant/AntiMod_localSecretKeySettings.jsonIf the file is missing, the editor property returns a new LocalSecretKeySettings with package defaults. Those values are not persisted until Fetch Encode Secret Key Settings is pressed.
This JSON file is used by editor/build workflows for:
- Android and iOS important file lists
- iOS known framework allowlist input before encoding
allowShowPathInIntegrityJsoniOSUnityFrameworkSecretKeyfor the injected Xcode shell scriptintegrityJsonFileinput before it is encoded into the asset
Important consequence:
the JSON file is not the runtime source of truth for secrets. Runtime uses the encoded fields stored in AntiModSettings.
Editor Workflow
Open/Create Settings
Menu:
XmobiTea Tools/AntiMod/Open SettingsIf the resource asset does not exist, editor code creates it automatically.
Generate Encoded Secret Fields
Inspector button:
Fetch Encode Secret Key SettingsThis action:
- writes
Assets/XmobiTea-constant/AntiMod_localSecretKeySettings.json - XOR-encodes the Android, iOS, and iOS UnityFramework secret strings
- XOR-encodes the AES key and IV source strings
- XOR-then-AES encodes
iOSKnownFilesInFrameworks - AES-encodes
integrityJsonFile - writes the encoded byte arrays back into
AntiModSettings
Important consequence:
editing the localSecretKeySettings fields in the inspector does not persist anything until this button is pressed.
This step is required before runtime validation can work correctly.
Current inspector quirk:
AES-encrypted known-framework names and integrityJsonFile are encoded using the AES key/IV already stored on AntiModSettings before the button writes newly edited AES key/IV bytes. If you change aesIVSecretKey, aesKeySecretKey, or xorKeyAes, press Fetch Encode Secret Key Settings once to store those AES values, then press it again so AES-dependent fields are regenerated with the stored values.
Post-Build Hook
CheckSumGenerateEditor.OnPostprocessBuild(...) runs after build.
Current limitation: the callback is registered for all Unity builds, but the implementation only has real Android and iOS paths. Any non-iOS build target is sent through the Android zip-entry generation path, so unsupported targets can fail during post-build unless the generator is disabled or guarded.
Android Follow-Up
For Android it:
- opens the built APK/AAB as a zip
- finds entries whose names end with
androidImportantFilePaths - hashes those entries
- generates integrity data
- writes
Assets/StreamingAssets/integrity.json - checks whether the built artifact already contains the decoded integrity file name from
AntiModSettings
Practical consequence: Android workflow may require building again after the first generation pass.
Current limitation:
generation always writes a physical file named integrity.json, so changing integrityJsonFile away from that default breaks the current Android flow.
iOS Follow-Up
For iOS it:
- scans the built Xcode project output for files whose relative paths end with
iOSImportantFilePaths - hashes those files
- generates integrity data
- writes
Assets/StreamingAssets/integrity.json - copies that file into
Data/Raw/<decoded integrity file name> - optionally injects an Xcode shell script that generates
ufsignature.txt
Current limitation:
generation still writes Assets/StreamingAssets/integrity.json, so changing integrityJsonFile away from the default also breaks the current iOS flow before the copy step can succeed.
Required Setup
- Open
XmobiTea Tools/AntiMod/Open Settingsto create or selectResources/XmobiTea AntiModSettings.asset. - Configure local secret values and important file lists in the custom inspector.
- Leave
integrityJsonFileasintegrity.jsonunless the code is changed to support renaming end-to-end. - Click
Fetch Encode Secret Key Settingsto save the local JSON and refresh the encoded runtime fields. If you changedaesIVSecretKey,aesKeySecretKey, orxorKeyAes, click it a second time. - Build the app so post-process generation can produce integrity data.
- On Android, be prepared to rebuild after the first pass if the tool reports missing integrity data.
- Call
await CheckSumChecker.TryValidate()early at app startup on device.
Basic Usage
using UnityEngine;
using XmobiTea.AntiMod;
public sealed class AntiModBootstrap : MonoBehaviour
{
private async void Start()
{
var result = await CheckSumChecker.TryValidate();
if (!result.isValid)
{
Debug.LogError("[AntiMod] Validation failed: " + result.error);
Application.Quit();
}
}
}Do / Don't
Do
- Do treat this package as a build-time plus runtime workflow.
- Do generate encoded settings before relying on runtime validation.
- Do call
TryValidate()on real device builds, not just in editor. - Do expect Android and iOS to behave differently.
- Do keep the important file lists aligned with the actual built output.
Don't
- Don't assume editor validation proves anything about a real build.
- Don't assume desktop or other non-mobile targets are meaningfully protected by the current runtime.
- Don't edit encoded runtime fields by hand.
- Don't rename
integrityJsonFilewithout also fixing the post-build generator. - Don't forget that Android may need a rebuild after integrity generation.
- Don't assume the iOS known-framework check is currently reliable.
Common Mistakes
Mistake 1: Using editor success as real validation
In editor, TryValidate() always returns success.
Mistake 2: Forgetting to generate encoded settings
If Fetch Encode Secret Key Settings was never run, runtime secrets and file name decoding can be invalid.
Mistake 3: Assuming the local JSON is the runtime secret source
The JSON drives editor/build generation. Runtime reads the encoded values stored in AntiModSettings.
Mistake 4: Renaming integrityJsonFile
Current generation still writes Assets/StreamingAssets/integrity.json, so custom names do not work end-to-end yet.
Mistake 5: Expecting Android first build to already contain generated integrity data
Current workflow generates that file in post-process, so the first Android build can legitimately ask for a rebuild.
Mistake 6: Assuming all player targets are protected
Current non-Android/non-iOS runtime path still loads and signature-checks the integrity payload, then falls back to the permissive editor checker without platform file checks.
Namespace
using XmobiTea.AntiMod;Package Metadata
- Package name:
com.xmobitea.changx.antimod - Unity version:
2022.3+ - License:
Apache-2.0
