Constant Obfuscation: Making 100 Stop Looking Like 100

After names and strings, the next thing a reader anchors on is constants. A damage cap of 100, a rate limit of 60, a flag mask of 7: these magic numbers are landmarks that connect code to meaning. If you know the game's max level is 100, you can search the script for 100 and land near the leveling logic instantly. Constant obfuscation exists to take those landmarks away.

Think of a treasure map with an X on it. The X is a magic number: it tells anyone glancing at the map exactly where to dig. Constant obfuscation erases the X and replaces it with a riddle that points to the same spot, like two steps past the sum of the rock count and the tree count. The treasure has not moved an inch, but a stranger now has to solve the riddle before they even know where to look.

The transform

Each literal is replaced by an expression that evaluates to the same value but does not contain it. The simplest versions use arithmetic identities; stronger versions mix bitwise and arithmetic operators, a family known as mixed boolean-arithmetic (MBA), which is much harder to simplify by eye:

const limit = 100;
const flags = 7;
if (user.score > limit) grant(flags);
const limit = (0x60 + 0b100);          // 96 + 4 = 100
const flags = (2 << 2) - 1;            // 8 - 1 = 7
if (user.score > (150 - 50)) {         // 100
  grant((3 ^ 4));                      // 7
}

Notice that the same value can be rewritten differently at each use site, so even the fact that two places share a constant disappears. With per-build randomization, the expressions themselves change on every output, so notes taken while reading one build do not transfer to the next.

Watch it fold straight back

Here is the honest weakness made visible. A constant expression is still constant, so any folding pass evaluates it right back to the original number. The tool below runs a real constant-folding pass over a program whose thresholds have been rewritten as arithmetic. Drag the slider and watch every disguised constant collapse to the plain value a reader was trying to hide. This is precisely what a decompiler or optimizer does automatically, which is why this layer is friction, not a wall, unless it lives somewhere folding cannot reach.

Why it raises cost

Grep for 100 now returns nothing. Every threshold, cap, and mask has to be recomputed by hand or by tooling before the reader even knows what they are looking at, and the visual noise slows comprehension of everything around it. Combined with renamed identifiers and encoded strings, the reader is left with structure and nothing else.

The honest limit

A constant expression is still constant, and compilers have been folding those since the 1960s. Any decompiler, optimizing pass, or symbolic execution tool will evaluate (0x60 + 0b100) back to 100 automatically, and even genuine MBA identities fall to specialized simplifiers given time. Alone, this transform is friction rather than protection.

The reason MBA resists simplification longer than plain arithmetic is that it deliberately crosses the boundary between two algebras: integer arithmetic (+, -, *) and bitwise logic (^, &, |, shifts). A rule like x + y equals (x ^ y) + 2 * (x & y) is true for all machine integers, but a simplifier has to reason across both domains at once to see it, which many peephole optimizers do not. Dedicated MBA solvers, often built on bit-blasting to a SAT or SMT engine, do crack a large fraction of published identities, so the honest posture is that MBA buys time proportional to the attacker's tooling, and its real value shows up once the expression lives in bytecode operands where there is no source-level expression for a folder to normalize at all.

Where constant obfuscation genuinely earns its place is inside a virtualized program, where the expressions live in bytecode operands rather than readable source, and the folding tools that would normalize them no longer have source to fold.

That pattern, weak alone but multiplicative when layered, repeats across every technique in this module, and it is the reason serious obfuscators stack transforms instead of betting on one.

Frequently asked questions

What is mixed boolean-arithmetic (MBA) obfuscation?

Rewriting values and operations as expressions that mix arithmetic (+, -, *) with bitwise operators (^, &, |), using identities that are hard to simplify visually. Example: x + y can become (x ^ y) + 2 * (x & y). Dedicated research tools can simplify many MBA forms, so it is a cost-raiser, not a wall.

Does a compiler undo constant obfuscation?

For plain constant expressions, yes: constant folding evaluates them right back. That is the technique's known limit and why it is deployed as one layer among several, ideally under virtualization where there is no source-level expression left to fold.

Keep learning

  • String Obfuscation: Hiding the Text Attackers Search First
  • Opaque Predicates: Branches Only the Author Can Trust
  • What Is Bytecode Virtualization?
  • Symbol Stripping vs Obfuscation for Go Binaries
  • JavaScript Obfuscator
  • Go Obfuscator

All lessons