- 23 Dec 2024
- 2 Minutes à lire
- SombreLumière
- PDF
Troubleshooting obfuscation
- Mis à jour le 23 Dec 2024
- 2 Minutes à lire
- SombreLumière
- PDF
Enabling full app obfuscation is in most cases a non-trivial task, that requires knowledge of the inner workings of the app, and all its components including any third party libraries.
Protecting the application with debug mode can be a useful way to troubleshoot obfuscation. This is done with the Shielding Tool command line option --debug.
There are only two ways obfuscation can fail:
Missing framework
Reflection.
Reflection includes uses of Class.forName, Class.getMethod, Class.getField and so on, as well as native library access of Java classes/members through JNI.
Custom views in layout xml files are also created through reflection, however the Shielding Tool attempts to parse through these xml files and updates references to these classes.
The issue of reflection is compounded by several factors that may make troubleshooting obfuscation much harder:
Crashlytics and similar crash reporting tools may consume exceptions making it harder to detect issues. If the app crashes too early, Crashlytics will not be able to report these crashes.
Exceptions from failed reflection may be caught and not output to console. This may however lead to issues later (like NullPointerException) when a different section of the code tries to use objects instantiated by the failed reflection.
Debugger in Android Studio is an invaluable tool in tracking down cases of reflection, because it will allow detection even when an UncaughtExceptionHandler is used, or when try/catches swallow exceptions that later lead to crashes.
To debug with Android Studio, follow these steps:
Compile/build app in debug mode
Compile/build app in debug mode
Go to Developer options on test device (or emulator). Enable Wait for debugger option.
Select app in Select app to be debugged
Start application. Device should display dialog with Waiting for debugger.
In Android Studio set breakpoints in strategic locations.
Class.forName, Class.getMethod, Class.getField
Constructor for java.lang.ReflectiveOperationException
Constructor for java.lang.NullPointerException
These breakpoints can be set to Evaluate and log instead of suspending. They can also be set to a condition, so they will only react when they are about to return null or throw an exception.
When navigating these classes make sure to select the source appropriate for the OS version on the device.
In Android Studio go to Run > Attach Debugger to Android Process. Select app in subsequent Choose process popup and click OK.
Debug through the app. Each time reflection is used or fails, verify whether the name requested in the reflection goes to the old pre-obfuscated name. If so, determine whether the code that performs this reflection can be updated to not use reflection, or add the requested names to the rules file so this name won’t be obfuscated.
Repeat Step 2, 7 and 8 until all reflection in the app is either avoiding reflection, or obfuscation.