When I obfuscate my code with Proguard, I have a line of code as follows:
String aString = getResources().getString(R.string.foo);
Even though I set my proguard configuration file to keep the R class an all its inner classes (and they're been kept), it obfuscates that line making foo a static field of a random renamed n class.
How can I make it not to make this specific change and inline the referred string at that point? Or reference the string by the id for that matter.
Give a try to -keepclassmembernames
It seems you are doing Android developing, in this case the default proguard configuration comes with Android Studio works perfect for me. If you are using other IDE, you can just copy that proguard configuration to your project.
Related
I have Unable to create application im.app.android.core.AppDemoApplication: e3.b: com.pushserver.android.huaweiPushClient cant cast com.myApp.android.push_lib.huawei.HcmPushClient to PushClient error
What proguard rule should I add? I have tried -keep class com.myApp.android.push_lib.** { *; } but after that I just see the blank screen - no crash, just stuck when trying to start.
Not really an answer, but too long for a comment. I'll update this answer in case we make progress.
1. What is the "normal bug"?
can't cast com.myApp.android.push_lib.huawei.HcmPushClient to PushClient
This means that somewhere in your code you are assigning/passing an instance of HcmPushClient to something that is expecting it to be a PushClient. I would assume that PushClient is some class that you defined in your project, but is does not extend from HcmPushClient. Try to find this piece of code and fix it or add it here to your question.
2. What does ProGuard have to do with this?
Actually, I think not much. If ProGuard would create this error, the message would look more like
can't cast com.myApp.android.push_lib.a.b to c
But since all class names in the error message are the original ones, it does not seem like ProGuard is making issues here. BUT: You can still decypher the message a little bit, because this part is obfuscated:
Unable to create application im.app.android.core.AppDemoApplication: e3.b:
e3.b refers to a class that was obfuscated by ProGuard. To find out what class it is, you can check the file /build/outputs/mapping/release/mapping.txt in your project folder. This is a simple text file that stores the information what class name was renamed to what obfuscated name. In this file search for -> e3 to find the class that was renamed to e3. Somewhere close to this line, you should also be able to find out what exactly e3.b is. Could be a method, could also be a member variable or an inner class.
I hope these two points will bring you closer to make the app run.
Because of just one wrong written line of code in FloatingToolbar.java i was force to copy the entire source code in my library to patch it. This work but now the problem is that this unit call also com.android.internal.R. The problem with com.android.internal.R is that it's could be different between release, (because it's internal), so to be safe i must also duplicate the definition
in r class i have for example :
public static final class layout {
public static final int floating_popup_open_overflow_button=xxx
}
where to find the xml (i think it's an xml?) that define floating_popup_open_overflow_button ? actually in \android-sdk-windows\sources\ i can find only the java files
where to find the xml (i think it's an xml?) that define floating_popup_open_overflow_button ?
You can find a copy in $ANDROID_SDK/platforms/android-NNN/data/res/layout/, where $ANDROID_SDK is wherever you have installed the Android SDK and NNN corresponds with the version of the Java that you forked. There may be other variants of floating_popup_open_overflow_button.xml in peer directories (e.g., layout-xlarge); I have not checked them all.
I have applied ProGuard to my Android application.
I'm using
android-studio/sdk/tools/proguard/proguard-android.txt
as a configuration file, changing nothing.
In this file I can see the only statement regarding Activity:
We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
It follows from that the Activities class names are obfusctated by ProGuard while some methods are preserved as they are. This is understandable.
However, in my application I then create an Activity Class from a string using
Class.forName("my.app.MyActivity")
then I start this Activity and it starts fine.
But that means Activity-derived classes are not obfuscated??. It should have failed because ProGuard does not have -keep class directive for Activity, it only has -keepclassmembers.
Can someone, please, explain, if I can rely on the behaviour I observe? Or do I misunderstand the -keepclassmembers directive?
Because the activities are listed in the manifest and classes referenced there are automagically kept. This is needed because the Android framework accesses these app entry points via reflection.
From here:
The build process runs the tool aapt to automatically create the configuration file bin/proguard.txt, based on AndroidManifest.xml and other xml files. The build process then passes the configuration file to ProGuard. So ProGuard itself indeed doesn't consider AndroidManifest.xml, but aapt+ProGuard do.
From the ProGuard FAQ:
Does ProGuard handle Class.forName calls?
Yes. ProGuard automatically handles constructs like Class.forName("SomeClass") and SomeClass.class. The referenced classes are preserved in the shrinking phase, and the string arguments are properly replaced in the obfuscation phase.
With variable string arguments, it's generally not possible to determine their possible values. They might be read from a configuration file, for instance. However, ProGuard will note a number of constructs like "(SomeClass)Class.forName(variable).newInstance()". These might be an indication that the class or interface SomeClass and/or its implementations may need to be preserved. The developer can adapt his configuration accordingly.
So, ProGuard's being cleverer than you expected: it will automatically detect and handle simple cases of the use for forName(). Even if the class isn't referenced in the Android manifest file, ProGuard will obfuscate the class name in both the class and in your call to forName().
For Activities, it wouldn't surprise me if you're doubly-covered by both this behaviour and by the Android-specific input to ProGuard that's part of the build process, as #laalto mentions in his answer.
I know in Proguard you are recommended to keep the fields names of the R inner classes like ID. Because ProGuard doesn't handle the layout xml files. You will end up with broken links
But is there away to obfuscate classes like R$id by some other means, even if it involves doing it before passing it to ProGuard, via Ant.
I am asking this because if you have a button with an id btnSaveArticle, for a hacker it becomes too easy to grasp what the code around is doing by looking at the name.
Could it be possible to copy all the source code, including the resource files to another folder and use ant to run regex to change the names of the R.ids as well as changing where they appear in the layout xml files, and then somehow running generate to re-create the R classes?
Or you could create translation class eg TR then map it to the fields in the R.class
eg.
TR.btnSaveArticle = R.id.DHTXM;
Where DHTXM is some meaning less word that can be used in the layout XML. But in the code you always refer to TR.btnSaveArticle, which will be obfuscated by proguard.
Are there ways to achieve this or am I wasting my time?
Just use below ,add it to you Proguard config file
-keepclassmembers class **.R$* {
public static <fields>;}
I am asking this because if you have a button with an id btnSaveArticle, for a hacker it becomes too easy to grasp what the code around is doing by looking at the name.
Using Hierarchy View, it would take them less than 30 seconds to determine the actual ID of the "Save Article" button, no matter what you name it. And I can envision even faster solutions with a bit of custom tooling.
am I wasting my time?
IMHO, yes.
With the default configuration for Android, ProGuard removes R classes entirely, unless your code performs introspection on them. In the latter case, ProGuard also preserves the fields with their original names, in order not to break the introspection.
That being said, the resource names can also be retrieved from the resource XML files, which ProGuard leaves untouched.
It is possible through Ant, as it allows you to set a different gen and res folder.
So what you do is copy from the originals to those folders and then you edit the files using regex to update to the new names.
You will need a translation class (eg D) like this to map it to the fields in the R.class, so in your code you can work with non obfuscated names.
public final class D{
public static final class id{
D.btnSaveArticle = R.id.btnSaveArticle //DHTXM;
Then you also need to create a different src folder and copy from the original folder. There you run a task to edit the D class so it becomes
D.btnSaveArticle = R.id.DHTXM;
I had to create a java program which is run through ant to swap the names to obfuscated names.
If you do something similar for strings, and styles your XML in the apk would end up looking like this:
<TextView
android:id="#+id/GnvCMa"
android:text="#string/OVuCbd"
style="#style/ZOVkuu.MGTRgZ" />
It is a little time consuming to setup, but once implemented it can be used for other projects.
I just used the new ProGuard tool in eclipse to obfuscation my application. The I decompiled it using dex2Jar and JD-GUI to inspect what happened.
I noticed that everything from the R class has been converted to a random number like the following.
new SimpleCursorAdapter(localActivity, 2130903058, localCursor, arrayOfString, arrayOfInt);
2130903058 was a layout file. Strings an arrays get the same treatment.
There is no R class in the decompiled code, where has it gone? Where are the references to the original strings?
All references are integers. If you look at R.string, you'll notice all the members are ints. This is because they are pointers to the actual strings. For example, android.R.string.cancel is always 17039360, which points to the string Cancel. What ProGuard does is it replaces these references with the actual numbers they represent, so if you use android.R.string.cancel, it will replace it with 17039360.
Edit: There is no R class because it is not needed anymore (all references to it have been replaced).