Book contents
Contents
raw Math
RAW Book Algorithms Bit Manipulation

Introduction to Bitwise Obfuscation Tricks

Robert Eisele

Obfuscation tricks rewrite ordinary boolean and arithmetic logic using bitwise identities, usually to shrink code, avoid branches, or simply disguise intent. Most of them boil down to a small set of properties of XOR, so it helps to first look at bit manipulation tricks for the underlying building blocks before treating them as a way of hiding rather than clarifying logic.

XOR as a Building Block

XOR is commutative and associative, satisfies \(x\oplus 0=x\), and cancels itself, \(x\oplus x=0\). The single most important consequence for obfuscation is that XOR detects equality:

\[ a\oplus b=0 \iff a=b, \]

since two values agree bit for bit exactly when none of their bits differ, and XOR sets a bit precisely when the corresponding input bits differ.

Increment and Decrement Through Complement

For a fixed-width two's-complement integer, bitwise complement and arithmetic negation are related by

\[ \mathop{\sim}x=-x-1. \]

Rearranging the same identity gives the usual two's-complement recipe for negation: invert every bit, then add one.

\[ -x=\mathop{\sim}x+1. \]

-3 == (~3) + 1

The parentheses make the operation explicit: first compute ~x, then add 1. This is different from ~(x + 1), which equals -x-2.

Negating both sides turns complement into an increment:

\[ -\mathop{\sim}x=x+1. \]

-~3 == 4

Complementing the negation of a value similarly produces a decrement:

\[ \mathop{\sim}(-x)=-(-x)-1=x-1. \]

~-3 == 2

The unary operators are evaluated from right to left, so -~3 means -(~3), whereas ~-3 means ~(-3). The two expressions therefore encode 3 + 1 and 3 - 1, respectively. They rely on the integer and bitwise semantics of the language: JavaScript, for example, converts Number operands to signed 32-bit integers before applying ~. It also produces -0 for -~(-1); that value compares equal to 0, but Object.is(-0, 0) is false. In the reverse identity, (~0) + 1 produces +0 rather than the -0 returned by unary -0. Ordinary arithmetic remains clearer and avoids such surprising conversions.

Equality Check via XOR

a = (!(a ^ b)) ? 1 : 0;

By the equality property above, \(a\oplus b\) is \(0\) exactly when \(a=b\), and nonzero otherwise. Logical negation ! maps \(0\) to \(1\) and any nonzero value to \(0\), so !(a ^ b) is already \(1\) exactly when \(a=b\) and \(0\) otherwise. The surrounding ternary is redundant, since !(a ^ b) is already a \(0\)/\(1\) value: the whole line computes nothing more than the ordinary comparison a == b, just spelled out through XOR instead of a direct equality operator.

Turning a Comparison Into a Zero Test

A more useful and genuinely reusable idea is that XOR-ing both sides of an equality by the same value preserves the equality, and likewise for inequality:

\[ a=b \iff a\oplus c=b\oplus c \qquad\text{for any } c. \]

The forward direction is immediate: applying \(\oplus c\) to both sides of \(a=b\) preserves the equation. For the converse, XOR both sides of \(a\oplus c=b\oplus c\) by \(c\) again; since \(x\oplus c\oplus c=x\), this cancels \(c\) on both sides and returns \(a=b\). Because XOR by a fixed constant is its own inverse, it never changes whether two values are equal, so it cannot change whether they differ either.

A common application picks \(c\) to be the comparison target itself, turning a test against a constant into a nonzero test. To check \(x\neq 1\):

\[ x\neq 1 \iff (x\oplus 1)\neq(1\oplus 1) \iff (x\oplus 1)\neq 0. \]

if (x ^ 1) { ... }   // true exactly when x != 1

This is why comparisons against small constants are often rewritten as an XOR followed directly by a truthiness test: in C-like languages, any nonzero value is already "true", so the explicit \(\neq 0\) never needs to be written out.

Branch-Free Conditional Negation

Combining XOR with a mask of all zero or all one bits, as used for absolute value, also gives a branch-free conditional negation. For a boolean condition represented as \(0\) or \(1\), let \(\text{mask}=-\text{cond}\), which is \(0\) when \(\text{cond}=0\) and all ones, \(\lnot 0\), when \(\text{cond}=1\):

result = (x ^ mask) + cond;

When \(\text{cond}=0\), \(\text{mask}=0\), so \(\text{result}=(x\oplus 0)+0=x\), unchanged. When \(\text{cond}=1\), \(\text{mask}\) is all ones, so \(x\oplus\text{mask}=\lnot x\), and \(\text{result}=\lnot x+1=-x\), the negation of \(x\). One expression therefore either passes \(x\) through unchanged or negates it, entirely without an if.

Written the other way around, as a ternary rather than an assignment, this is exactly the identity \(y\ ?\ {-v}\ :\ v \iff (v\oplus{-y})+y\) for \(y\in\{0,1\}\): swapping which branch gets negated only swaps the sign convention of the mask, not the underlying mechanism.

Expanding a Boolean Flag to a Mask

A \(0\)/\(1\) flag can be expanded into a mask of either all zero bits or all one bits with a single negation:

mask = -(x & 1);   // 0x00000000 if x is even, 0xFFFFFFFF if x is odd

\(x\ \&\ 1\) isolates the lowest bit of \(x\), giving exactly \(0\) or \(1\). Negating \(0\) leaves \(0\); negating \(1\) in two's complement gives \(-1\), whose representation is all one bits. This turns a single boolean bit into the all-zero or all-one mask that the branch-free tricks above rely on, without a comparison or a shift.

Returning a Value Only When It Is Even

result = ((x & 1) - 1) & x;

\(x\ \&\ 1\) is \(0\) when \(x\) is even and \(1\) when \(x\) is odd. If \(x\) is even, this is \((0-1)\ \&\ x=(-1)\ \&\ x=x\), since \(-1\) is all ones and ANDing with it changes nothing. If \(x\) is odd, this is \((1-1)\ \&\ x=0\ \&\ x=0\). The expression therefore computes the same result as the plain conditional x % 2 ? 0 : x, using only a mask and an AND instead of a comparison and a branch.

Absorbing a Mask Into a Sub-expression

Whenever the outcome of an expression is going to be ANDed with a mask \(z\) anyway, any sub-expression already inside that AND can itself be pre-masked with \(z\) without changing the result:

\[ (x\lor y)\land z \iff \big(x\lor(y\land z)\big)\land z. \]

Distributing AND over OR gives \((x\lor y)\land z=(x\land z)\lor(y\land z)\) directly. Doing the same to the right-hand side gives \(\big(x\lor(y\land z)\big)\land z=(x\land z)\lor\big((y\land z)\land z\big)=(x\land z)\lor(y\land z)\), using \(z\land z=z\). Both sides reduce to the same expression, \((x\land z)\lor(y\land z)\), so they are equal. This lets an obfuscated expression bury an extra mask deep inside a sub-expression, where it looks like it changes the logic, while the final AND with \(z\) quietly cancels out any difference.

Common Pitfalls