Constant Mutation
Protection ID: constantMutation
Constant Mutation transforms numeric constants in your bytecode into equivalent arithmetic expressions. A simple int timeout = 30000 becomes a chain of operations that evaluates to the same value at runtime, preventing attackers from searching for known values.
Configuration
shield {
protections {
constantMutation = true
}
}shield {
protections {
constantMutation = true
}
}How It Works
Constant mutation replaces numeric literals in your code (integers, longs, doubles, and other numeric types) with arithmetic expressions that evaluate to the same value at runtime. This prevents attackers from identifying important values like buffer sizes, timeouts, retry limits, error codes, and other magic numbers during static analysis.
The protection decomposes each constant into a chain of randomly selected operations, so the same value produces different expressions on each build. This makes it impractical to write a pattern-based tool to recover the original values.
Before Shield
private static final int MAX_RETRIES = 3;
private static final long TIMEOUT_MS = 30000L;
private static final int BUFFER_SIZE = 4096;private static final int MAX_RETRIES = 3;
private static final long TIMEOUT_MS = 30000L;
private static final int BUFFER_SIZE = 4096;After Shield
private static final int MAX_RETRIES = ((7 ^ 4) - (12 >> 2)) + ((~(-5)) - 1);
private static final long TIMEOUT_MS = ((16384L * 2) - (1024 << 1)) + (((~(-769L))));
private static final int BUFFER_SIZE = (2048 << 1) ^ (0);private static final int MAX_RETRIES = ((7 ^ 4) - (12 >> 2)) + ((~(-5)) - 1);
private static final long TIMEOUT_MS = ((16384L * 2) - (1024 << 1)) + (((~(-769L))));
private static final int BUFFER_SIZE = (2048 << 1) ^ (0);Each constant is transformed using a different combination of operations, so patterns cannot be generalized.
Operation Categories
Shield uses 43 operations across 6 categories to transform constants:
| Category | Operations | Example |
|---|---|---|
| Arithmetic | Add, subtract, multiply, divide, remainder | (15 * 2) + 1 |
| Conditional | Inline conditionals, comparisons | (x == x) ? 31 : 0 |
| Logical | AND, OR, XOR, NOT | (0xFF ^ 0xE0) |
| Shift | Left shift, right shift, unsigned right shift | (1 << 12) |
| Conversion | Type casts between numeric types | (int)(30000.0) |
| Mixed | Chained operations from multiple categories | ((7 ^ 4) - (12 >> 2)) |
Operations are chained: a single constant may be decomposed into 3 to 6 nested operations, each randomly selected.
Excluding Constants
Use the @Exclude annotation to skip constant mutation for specific elements:
import com.bytehide.shield.annotations.Exclude;
@Exclude(protections = {"ConstantMutation"})
public class MathConstants {
public static final double PI = 3.14159265358979;
public static final double E = 2.71828182845904;
}import com.bytehide.shield.annotations.Exclude;
@Exclude(protections = {"ConstantMutation"})
public class MathConstants {
public static final double PI = 3.14159265358979;
public static final double E = 2.71828182845904;
}Performance Impact
Constant mutation adds negligible runtime overhead. The arithmetic expressions are evaluated by the JVM at load time or JIT-compiled to the original constant value. The cost is primarily in bytecode size, not execution speed.
When to Use
Constant mutation is recommended for all production builds. It is especially useful for applications that use magic numbers for license validation, timeout or retry values that reveal server behavior, error codes that map to internal states, buffer sizes and limits that reveal implementation details, or any numeric values that could aid reverse engineering.
Related
- String Encryption - Protect string literals
- Control Flow Obfuscation - Restructure method logic
- Protections Overview - All available protections