Arithmetic Encoding
| Plan | Platforms | MASVS |
|---|---|---|
| Team | Android | MASVS-RESILIENCE-3 |
Overview
Arithmetic Encoding is a build-time obfuscation control that transforms numeric constants in compiled bytecode into semantically equivalent but syntactically complex arithmetic expressions. Instead of storing literal values like 5 or 0x1234, the control replaces them with expressions such as (0xC ^ 0x9) or compound operations involving XOR, addition, and negation that evaluate to the original value at runtime.
This transformation operates at the Dalvik bytecode (smali) level after compilation but before packaging, ensuring no source code changes are required. The technique defeats constant-propagation optimizations in decompilers (jadx, Procyon, CFR) by forcing them to display complex expressions or partially-reduced forms, significantly increasing the difficulty of reverse engineering business logic, cryptographic keys, API endpoints, and other hard-coded values.
Arithmetic Encoding is probabilistic: each build applies transformations randomly, so repeated compilations produce different bytecode representations of the same constants. The control implements a global cap of 2,000 encodings per build to balance obfuscation strength against APK size inflation.
How It Works
Arithmetic Encoding operates during the AppTego Android protected build pipeline after the app is compiled to Dalvik bytecode but before final APK/AAB assembly. The process modifies .smali files (human-readable Dalvik bytecode representation) directly:
Transformation Patterns
The control applies several encoding strategies depending on the constant size and register constraints:
- XOR Split (const/4, const/16, const):
- Original:
const/4 v0, 3 - Transformed:
const/16 v0, 0x1B+xor-int/lit8 v0, v0, 0x18 - Result:
0x1B ^ 0x18 = 0x03
- Addition Split:
- Original:
const/16 v1, 500 - Transformed:
const/16 v1, 450+add-int/lit8 v1, v1, 50 - Result:
450 + 50 = 500
- Negation Chain:
- Original:
const/16 v2, -42 - Transformed:
const/16 v2, 42+neg-int v2, v2 - Result:
-(-42) = 42(double negation)
- Wide Constant Encoding (const-wide/16):
- Original:
const-wide/16 v0, 1000L - Transformed:
const-wide/16 v0, -1000L+neg-long v0, v0 - Result:
-(-1000L) = 1000L
Each transformation is applied with 33–50% probability per instruction, and the specific arithmetic operation (XOR vs. addition vs. negation) is chosen randomly, ensuring diversity across builds.
Scope and Exclusions
- Included: All application and third-party library code compiled into the app's
smali/directory - Excluded: Android framework classes (
android/,androidx/,com/google/android/,kotlin/,kotlinx/) - Skipped: Zero-valued constants (to preserve null checks and type safety), registers used as float operands, abstract/native methods
Float Safety
The control includes type-analysis logic to prevent transforming integer constants that are later used in floating-point operations (e.g., cmpl-float, div-float). Applying integer arithmetic (XOR, add) to a constant loaded into a register that will be interpreted as a float causes Android's bytecode verifier to reject the DEX file due to type conflicts at merge points. The float-detection heuristic scans ahead in the method body to identify such usage patterns and skips those constants.
Performance Impact
Arithmetic Encoding introduces minimal runtime overhead (typically <1ms per encoded constant) since the expressions are simple two-instruction sequences that execute at native CPU speed. The primary cost is increased APK size: each encoding adds 2–4 bytes of bytecode. The 2,000-encoding cap typically results in 4–8 KB of additional DEX code, well within the "insignificant" threshold for modern devices.
How to Enable the Control
Navigate to Code Obfuscation from the AppTego portal, and expand the Code And String Protection section. Under this section you will find the Arithmetic Encoding control. Click Enable to apply it to the next protected build.
API Configuration Example
{
"ArithmeticEncoding": {
"protection": true
}
}
| Field | Purpose |
|---|---|
protection | Enables arithmetic encoding for protected builds. |
Threats Mitigated
- Constant-Propagation Analysis: Decompilers rely on constant-propagation passes to simplify code. When a constant is replaced with
(A ^ B), the decompiler either displays the complex expression verbatim or partially reduces it (e.g.,var2 = (27 ^ 24)), forcing reverse engineers to manually compute values or rely on dynamic analysis.
- Magic Number Search: Attackers frequently use string/number search tools (e.g.,
grep, IDA's "immediate value" search) to locate cryptographic keys, API version codes, feature flags, or license check constants. Arithmetic Encoding eliminates literal matches, requiring adversaries to execute the app or manually trace expressions.
- Automated Deobfuscation: Mass-decompilation tools that batch-process APKs for pattern matching (e.g., malware analysis pipelines, app store analyzers) are slowed by the need to symbolically evaluate each arithmetic expression. This increases the cost of large-scale reverse engineering campaigns.
- Static Binary Diffing: When constants are deterministically encoded across builds, attackers can use binary diff tools to identify code changes between app versions. Probabilistic encoding produces different bytecode on each build, breaking diff-based patch analysis.
Caveats
- Not a Security Primitive: Arithmetic Encoding is a speed bump, not a cryptographic protection. It is best used with anti-tampering controls, hook detection, root detection, and emulator detection.
- Increased APK Size: Each encoding adds 4–12 bytes of bytecode (depending on the transformation type). The 2,000-encoding cap typically adds 4–8 KB to the DEX file. Apps with extremely tight size budgets may observe minor inflation (0.01–0.02% of typical APK size).
- Decompiler Variability: Some decompilers (e.g., jadx 1.4.7+) can partially reduce simple expressions like
x + (-5)back tox - 5. The obfuscation effectiveness depends on the attacker's toolchain; however, even partial reduction still increases cognitive load compared to bare constants.
- Reversible Transformation: Each encoded constant can be symbolically reduced by solving the arithmetic expression. This control does not provide irreversibility—its value is in forcing manual analysis and increasing the time cost of reverse engineering.
Support Matrix
| Platform | Minimum Version | Plan Requirement |
|---|---|---|
| iOS | Not supported | — |
| Android | API 21+ (5.0 Lollipop) | TEAM |
Build Pipeline Requirement: Android AppTego protected build pipeline (AppTego protected build workers). Apps built locally via gradlew or CI/CD without MobileDefender's AppTego protected build pipeline will not receive this obfuscation.
Plan Requirement
TEAM plan or higher is required to enable Arithmetic Encoding. The control is gated in ObfuscationManager.java via subscription tier check and must be explicitly enabled in the customer's obfuscation_controls configuration array.
To enable, ensure "ArithmeticEncoding" is present in the app's configuration JSON:
{
"obfuscation_controls": [
"ArithmeticEncoding"
]
}
If the subscription is TEAM or higher and the control is listed, it will be applied automatically during the next app build.