Determinism & seeds¶
Obfuscation is randomised, but not unpredictable. Given the same input and the same seed, xollvm produces byte-identical output — essential for reproducible builds, debugging, and auditing what shipped.
The seed cascade¶
Seeds derive top-down, so every pass on every function gets its own stable stream without any two passes sharing state:
flowchart TD
B["base seed<br/>-obf-seed=N"] --> M["module seed<br/>hash(base, module id)"]
M --> F1["function seed<br/>hash(module, fn name)"]
M --> F2["function seed<br/>..."]
F1 --> P1["pass seed<br/>hash(function, pass id)"]
F1 --> P2["pass seed<br/>..."]
Each level is a stable hash of the level above plus a stable key (module identifier, function name, canonical pass id). Nothing depends on hash-map iteration order or wall-clock time.
Controlling the base seed¶
| Flag | Effect |
|---|---|
-obf-seed=<N> |
Pins the base seed. Any non-zero value makes every run reproducible. |
-obf-deterministic |
When the seed is 0, derive the module seed from a hash of the module identifier instead of random_device. |
Recommended during development and for release builds alike:
Seed 0 without -obf-deterministic is non-reproducible
With seed 0 and no -obf-deterministic, the module seed comes from random_device — output
changes every run. Fine for shipping diversity; bad for debugging. Pin a seed while developing.
The seed manifest¶
For auditable builds, dump the full derived-seed tree:
| Flag | Effect |
|---|---|
-obf-seed-manifest=<path> |
Write a JSON manifest (base / module / function / pass seeds). - writes to stderr. |
-obf-seed-manifest-md |
Also embed per-pass seeds into IR metadata (obf.seed.manifest.<passId>). |
opt -passes=obfuscation app.ll -S -o app.obf.ll \
-obf-seed=1 -obf-deterministic -obf-seed-manifest=seeds.json
The manifest lets you reproduce a specific historical build exactly, or diff two builds to confirm only the intended functions changed.
Build diversity vs reproducibility¶
The two goals are a single knob:
- Reproducible (CI, debugging, signed releases): fix
-obf-seed=<N>. - Per-build diversity (ship a different binary each release to defeat signature matching): vary the seed per build — e.g. derive it from the version or a build counter — and archive the manifest so you can still reproduce any given build later.
See Reproducible builds for a full workflow.