Code obfuscation
Skill almasumdev/awesome-mobile-security-agent-skills/.github/skills/code/code-obfuscation
Agent skills for securing mobile apps: storage, transport, auth, obfuscation, and hardening.
npx -y skills add almasumdev/awesome-mobile-security-agent-skills --skill code-obfuscationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Code obfuscation on mobile — R8 / ProGuard on Android, SwiftShield and its limitations on iOS, and realistic expectations. Use when hardening release builds.
SKILL.md
5.0 KB, as published. Nobody here has run it
Code Obfuscation
Instructions
Obfuscation raises the cost of reverse engineering, it does not prevent it. Treat it as speed bumps, not walls.
1. What Obfuscation Actually Buys You
- Slows down static analysis with Jadx / Ghidra / Hopper.
- Strips logging and debug symbols from release builds (real value).
- Makes automated tooling (Frida scripts pattern-matching on class names) more brittle.
What it does not buy:
- Protection against dynamic instrumentation (Frida, Objection).
- Protection for anything the app actually needs to do — a debugger will see it.
- A substitute for server-side authorization.
2. Android: R8 in Release
R8 is the modern replacement for ProGuard and ships with AGP. Enable both shrinking and obfuscation for release:
// app/build.gradle.kts
android {
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}
}
Common proguard-rules.pro hygiene:
# Keep Kotlin metadata for reflection-heavy libs (Moshi, Retrofit)
-keep class kotlin.Metadata { *; }
# Retrofit + OkHttp
-keepattributes Signature, InnerClasses, EnclosingMethod
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
-keep,allowobfuscation,allowshrinking class retrofit2.Response
# Models read via reflection (adjust to your package)
-keep class com.example.app.dto.** { *; }
# Strip logs in release
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** i(...);
}
Pitfalls:
- Serialization libraries (Gson/Moshi/kotlinx-serialization) and reflection: every model read by reflection needs a
-keep. - JNI / native methods: keep the
nativemethod signatures exactly. - DI frameworks (Hilt, Koin) usually ship their own consumer rules — don't duplicate.
3. Android: Strip Debug Symbols From Native Libs
android {
packaging {
jniLibs {
useLegacyPackaging = false
}
}
buildTypes {
release {
ndk { debugSymbolLevel = "none" } // or "symbol_table" for Play upload only
}
}
}
Upload symbols to Play separately so your crash reports remain readable.
4. iOS: Symbol Stripping
Swift doesn't have an R8. The standard hardening:
- In Release build settings:
Strip Debug Symbols During Copy = YESStrip Swift Symbols = YESDeployment Postprocessing = YESSymbols Hidden by Default = YES
- Archive dSYMs separately and upload to your crash reporter.
5. SwiftShield and Friends — Read the Fine Print
SwiftShield renames Swift symbols post-build. Known issues:
- Can break Objective-C interop and
@objcselectors. - Can break
Codable,NSKeyedArchiver, and any reflection-based serializer. - Incompatible with some SDKs that assume class names at runtime.
Use it only if:
- You have a threat model (financial, DRM, gaming) that justifies the fragility.
- You have end-to-end UI tests that run against the obfuscated binary on every PR.
- You accept the maintenance cost.
For most apps, proper symbol stripping + release-mode assert/log removal is enough.
6. React Native / JavaScript
- Enable Hermes and
minify: trueinmetro.config.jsfor release. - Use
babel-plugin-transform-remove-consoleto stripconsole.*. - Do not rely on JS obfuscators (
javascript-obfuscator) for secrets — they're trivially reversible.
7. Flutter / Dart
- Use
flutter build apk --obfuscate --split-debug-info=build/symbols/. - Upload the split debug-info directory to your crash reporter (Crashlytics / Sentry) so stack traces remain readable.
- Dart obfuscation renames symbols but the bytecode structure remains — it is still reverse-engineerable.
8. What to Actually Hide
Rank your concerns:
- Nothing sensitive in the binary — no API keys, no hard-coded JWTs, no endpoints that only "security through obscurity" protects.
- Strip logs and debug scaffolding from release.
- Strip symbols / obfuscate names as a speed bump.
- Only then consider paid RASP / commercial obfuscators, and only if a real threat model requires them.
Checklist
- R8 (
isMinifyEnabled = true) is on for release on Android. - Consumer ProGuard rules for every reflection-heavy library are present.
- Native debug symbols are stripped from the release APK / AAB; symbols uploaded to Play.
- iOS release strips Swift & debug symbols; dSYMs uploaded to crash reporter.
- SwiftShield / similar is only used with a documented threat model and UI tests.
- Flutter release uses
--obfuscate --split-debug-info; symbols uploaded. - Nothing security-relevant relies on the name of a class remaining hidden.