Skip to content

Virtual call — vcall

Virtualises selected direct calls through synthetic vtables and indirection layers. Each transformed call site looks up its target through a generated table, optionally with decoy entries and per-callsite index-expression variation — so a static reader can no longer read the callee off the call instruction.

Options

Key Default Range Meaning
prob 30 0–100 Probability (%) to virtualise an eligible call site.
maxSites / max / sites 0 0–100000 Cap on call sites (0 = auto).
opaqueVTableNames 1 0/1 Hash-based naming for generated globals.
addDecoyEntries 1 0/1 Add decoy vtable entries pointing to safe stubs.
decoyMin 2 0–64 Minimum decoy entries per table.
decoyMax 4 0–64 Maximum decoy entries per table (must be ≥ decoyMin).
varyIndexPerCallsite 1 0/1 Vary the index expression per call site.
indexStrength 2 0–3 Index obfuscation strength level.
mergeVTables 0 0/1 Merge vtables across compatible callees (experimental).
encryptTable / encTable 0 0/1 Encrypt vtable entries, filled at runtime by a ctor (non-merged only).

Example

__attribute__((annotate("obf: vcall(prob=35,indexStrength=2,decoyMin=2,decoyMax=6)")))
int dispatch(int op) { return handler(op); }

Decoys + encrypted tables

addDecoyEntries=1 seeds each table with plausible-but-wrong targets; encryptTable=1 keeps the real entries as ciphertext until a load-time constructor fills them, so the table is not readable at rest. Combine with a high indexStrength to obscure which slot is actually selected.