Opaque Predicates

Opaque predicates insert conditions into your code whose result is fixed and known to the obfuscator, but impossible for an attacker to determine through static analysis.

  • AndroidAndroid
  • AppleiOS
TL;DR

An opaque predicate is a condition whose outcome is always the same, and the obfuscator knows it, but an analyzer cannot prove it. Opaque predicates are used to add branches that look real, anchor dead code, and make control flow impossible to follow with confidence.

Definition

What is an opaque predicate?

An opaque predicate is a conditional expression whose result is predetermined. It always evaluates true, or always false, but the value cannot be deduced by static analysis without effectively running the code.

On their own, opaque predicates do nothing visible. Their power is what they enable. They are the building block that makes dead code look reachable and makes obfuscated control flow resistant to analysis.

When an attacker analyzes a method, they need to know which branches can execute. Opaque predicates make that question unanswerable from the code alone, forcing slow, uncertain analysis.

Mechanism

How opaque predicates work

Opaque predicates are constructed from properties that are mathematically guaranteed but hard to evaluate statically:

  • Always-true and always-false conditions. Expressions built so their result is fixed but not obvious.

  • Anchoring dead code. A branch guarded by an opaque predicate can hold decoy code that appears reachable.

  • Supporting control flow obfuscation. Flattened control flow uses opaque predicates so the state transitions cannot be predicted.

The analyzer sees a real branch and cannot rule it out, so it must consider every path.

Example

Opaque predicates example

The same method, before and after opaque predicates are inserted. Both behave the same. Only one of them looks predictable to a decompiler.

Original

A decompiler can determine which branches are reachable and prune the rest, simplifying its view of the method.

With opaque predicates

Every branch looks possible. The decompiler cannot prune anything, and the method stays as complex as the obfuscator made it.

Original
fun process(input: String) {
    if (input.isNotEmpty()) {
        send(input)
    }
}
With opaque predicates
fun process(input: String) {
    val x = System.currentTimeMillis() and 0xFL
    if ((x * x + x) % 2L == 0L && input.isNotEmpty()) {
        send(input)
    } else if ((x * 7L) % 3L > 4L) {
        decoy()
    }
}

Use cases

When to use opaque predicates

Opaque predicates are most useful when your application:

  • Uses control flow obfuscation and needs it to resist analysis.
  • Uses dead code injection and needs the decoys to look reachable.
  • Must resist automated decompilers that prune unreachable code.

Opaque predicates are rarely used alone. They are the mechanism that makes control flow obfuscation and dead code injection effective.

Platform availability

Opaque predicates across platforms

  • Android

    Opaque predicates injected into bytecode control flow.

  • iOS

    Opaque predicates inserted during binary compilation.

Frequently asked questions

What is an opaque predicate?
An opaque predicate is a condition whose result is always the same and known to the obfuscator, but impossible for a static analyzer to determine. It is used to add branches that look real and to anchor dead code.
Do opaque predicates affect performance?
The impact is minimal. Each predicate is a small expression evaluated once where it appears.
What are opaque predicates used for?
They make obfuscated control flow resistant to analysis and make injected dead code appear reachable. They are a building block rather than a standalone protection.
Can opaque predicates be detected?
Advanced analysis can identify some patterns over time, which is why a strong implementation varies the constructions used. The goal is to make pruning unreliable.
Which platforms support opaque predicates?
ByteHide Shield uses opaque predicates on Android and iOS, and as part of control flow obfuscation on .NET and JavaScript.
10,000+ developers and companies protect their applications with ByteHide

Protect your application with
ByteHide Shield

Opaque predicates are one of more than 20 protections in ByteHide Shield. Apply them to your Android or iOS application.

ByteHide runtime dashboard showing live threat monitoring and protection metrics