Back to Blog

Resource Obfuscation with AndResGuard: What It Really Buys You

5 min read·2026-08-26

Renaming res/ paths is the cheapest hardening layer there is — and the one most likely to break your build if you skip the whitelist.

AndResGuard is the first layer VALLUM applies, and it is the best value-per-risk step in the whole pipeline. It rewrites res/ paths and resource table entries to short opaque names and recompresses the archive with 7za. There is no runtime behaviour change, no native dependency, no ART interaction — which is why it is also the layer with the best compatibility record. In most builds it shrinks the APK rather than growing it.

What it defends against is reconnaissance rather than theft. Attackers locate business logic by grepping resource names: a layout called activity_payment or a drawable named ic_premium tells you where to look before you have read a line of Smali. Renaming everything to r/a, r/b destroys that index. It also raises the cost of asset scraping and of repackaging flows that rely on fixed resource identifiers. It does not encrypt your assets — if you ship a secret in raw/, obfuscation is not the fix.

The failure mode is naming that must survive. Launcher icons, anything referenced from outside the app (notification drawables on some OEMs, app-widget layouts, shortcuts), resource IDs touched by reflection, and third-party SDKs that resolve resources by name string rather than compiled ID all break when renamed. AndResGuard takes a whitelist for exactly this; VALLUM keeps ic_launcher and friends in it by default. If your app crashes with Resources.NotFoundException after hardening, the whitelist is the first place to look, not the packer.

There is a second-order benefit that surprises people: because AndResGuard recompresses with 7za at maximum settings and shortens thousands of path strings, the size reduction is often measurable even on an already-minified build. On resource-heavy apps this single layer has paid for the size added by every later layer combined. That is a rare thing in hardening, where most steps cost size.

Order matters. Resource renaming must run before anything that rewrites the DEX, because the DEX references resources by compiled ID and both the resource table and the DEX must agree. Run it after R8 (so you are obfuscating the final resource set) and before dpt-shell. Running it last produces an APK whose resource table no longer matches what the code asks for — a class of bug that presents as a crash on first layout inflation, far from the actual cause.

Keep the mapping file. AndResGuard emits one, and you will want it the day a production stack trace arrives showing a resource name you cannot decode. Store it alongside your ProGuard mapping in whatever artefact store you already use — a mapping file nobody can find is a mapping file you do not have.