I'm trying to deobfucate a stack trace from my Android app. I used proguard when building the app and running retrace seem to work, more or less.
What isn't working is decoding the line numbers. No line numbers are shown on the output and it lists several choices for each "at".
Here is my proguard-project.txt file:
-keepattributes LineNumberTable
-assumenosideeffects class android.util.Log {
public static int v(...);
public static int d(...);
}
This is my stack trace:
uncaught exception
java.lang.NullPointerException
at com.myapp.myapp.dbaccess.ag.a(Unknown Source)
at com.myuapp.myapp.dbaccess.x.a(Unknown Source)
at com.myapp.myapp.dbaccess.x.a(Unknown Source)
at com.myapp.myapp.main.ab.run(Unknown Source)
And here is the output:
uncaught exception
java.lang.NullPointerException
at com.myapp.myapp.dbaccess.ZNodeCache.com.myapp.myapp.dbaccess.ZNode getNodeFromCache(long)(Unknown Source)
com.myapp.myapp.dbaccess.ZRoot getRootFromCache()
com.myapp.myapp.dbaccess.ZNode getNodeFromDb(long,boolean)
com.myapp.myapp.dbaccess.ZNode$Array getChildrenForExport(com.myapp.myapp.dbaccess.ZNode)
... many more ...
at com.myapp.myapp.dbaccess.XmlImport.com.myapp.myapp.dbaccess.XmlImport$Results importFile(java.lang.String)(Unknown Source)
void _doImport(java.io.InputStream,com.myapp.myapp.dbaccess.XmlImport$Results)
void importFile(java.io.InputStream)
void importNode(org.xmlpull.v1.XmlPullParser,com.myapp.myapp.dbaccess.ZNode)
... many more ...
at com.myapp.myapp.dbaccess.XmlImport.com.myapp.myapp.dbaccess.XmlImport$Results importFile(java.lang.String)(Unknown Source)
void _doImport(java.io.InputStream,com.myapp.myapp.dbaccess.XmlImport$Results)
void importFile(java.io.InputStream)
void importNode(org.xmlpull.v1.XmlPullParser,com.myapp.myapp.dbaccess.ZNode)
... many more ...
at com.myapp.myapp.main.MainActivity$3.void run()(Unknown Source)
I must be missing another configuration parameter; any ideas?
Turns out the answer is in the Android documentation (believe it or not). I guess I missed it the first time around. You need to specify the source file, like this:
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
The renamsesourcefileattribute will cause all source files to have the name SourceFile (or whatever you put). "retrace" doesn't care what the source file name is, but if you leave it out, it decides to ignore the line numbers.
This goes in proguard-project.txt which, if you're using Android Studio, you'll find in "your project".app.
Related
This is similar to Rejecting class because it failed compile-time verification Android and java.lang.VerifyError: Verifier rejected class on Lollipop when using release APK but the origin of my problem is still unknown and all the proposed solutions do not help.
Manually installing a signed release apk with MultiDex support and ProGuard enabled throws this exception on start:
475-475/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: ..., PID: 475
java.lang.VerifyError: Verifier rejected class android.support.g.b due to bad method void android.support.g.b.<init>() (declaration of 'android.support.g.b' appears in /data/app/...-2/base.apk)
at ...MyApp.attachBaseContext(Unknown Source)
at android.app.Application.attach(Application.java:181)
This will not happen with -dontoptimize. Current minimal optimization setting:
-optimizations "code/*"
I get the same error without -optimizations or with less restrictive options. Adding -keep class android.* wont help either. I get no error with "code/removal/*,code/simplification/*", but this ignores -assumenosideeffects
android.support.g.b is the obfuscated android.support.multidex.MultiDex class itself, and the error is caused when the overridden attachBaseContext(Context) is called:
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
Decoding this method (the default constructor) with the byte code viewer results in:
private b() { // <init> //()V
return
}
It would be useful to disable optimization by class specification.
Alternative: Knowing the minimum -optimizations option that considers -assumenosideeffects
Do not use member wildcards with -assumenosideeffects because this will "spill over" to Object for other classes. See https://sourceforge.net/p/proguard/bugs/716/#98d4
Similar problems may come up for any rules with interfaces. Example:
-assumenosideeffects class * implements Interface {
public <init>();
public Object interfacemethod(); # May concern methods with same signature in other Objects
}
Here are few lines from proguard-rules.pro
-keepattributes *Annotation*
-keepattributes Signature
-keepattributes InnerClasses,EnclosingMethod
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-keep public class * extends java.lang.Exception
-dontwarn org.apache.http.**
Logcat output (error line number is listed as 1133, while my source file is 100 lines longer)
09-04 16:11:46.698 3827-5280/com.XX.main E/AndroidRuntime: FATAL EXCEPTION: IntentService[ActivityRecognizedTracker]
Process: com.XX.main, PID: 3827
java.lang.NullPointerException: Attempt to read from field 'double com.XX.trips.Trip.a' on a null object reference
at com.XX.ActivityRecognizedTracker.onHandleIntent(SourceFile:1133)
I am preserving the line numbers and source file attributes, but stack trace is still obfuscated. What am I doing wrong?
AFAIK it's not possible to obfuscate the code and have original stacktraces. So if you want to see original method and class names in the stacktrace, you have to add -dontobfuscate rule.
But you don't really need the original stacktrace.
You are using -keepattributes SourceFile,LineNumberTable and that enables you to unambiguously retrace the stacktrace. Just don't forget to keep the generated mapping.txt file.
Moreover if you remove -renamesourcefileattribute SourceFile you'll see the original file names in the parentheses. The line number is already there, so you should be able to figure out without retracing where the exception actually happened.
I am using ProGuard in my application and problem is when users report some problem to my console and I can't decode it precisely because of "Unknown source".
Here is example of stacktrace:
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
at com.my.package.j.a(Unknown Source)
at com.a.a.c.c.j(Unknown Source)
at com.a.a.c.c.b(Unknown Source)
at com.a.a.c.e.run(Unknown Source)
at java.lang.Thread.run(Thread.java:856)
Then I am using this code to decode it:
./retrace.sh -verbose mapping.txt stacktrace.txt > out.txt
And here is output:
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
at com.my.package.MyFragment$10.void output(int,java.lang.String)(Unknown Source)
at com.stericson.RootTools.execution.Shell.void readOutput()(Unknown Source)
at com.stericson.RootTools.execution.Shell.void closeCustomShell()(Unknown Source)
com.stericson.RootTools.execution.Shell startShell(int)
void access$200(com.stericson.RootTools.execution.Shell)
at com.stericson.RootTools.execution.Shell$2.void run()(Unknown Source)
at java.lang.Thread.run(Thread.java:856)
It only shows name of Fragment when error occurred, but I also need exact line and method.
Your question has actually two parts.
1) Why are you missing the line information?
You are removing the line information during obfuscation. You need the following rules in your proguard.cfg
-renamesourcefileattribute MyApplication
-keepattributes SourceFile,LineNumberTable
Find details for retracing line numbers here: http://proguard.sourceforge.net/manual/retrace/examples.html#with
2) Why is it missing some method/class name, in your example
com.my.package.MyFragment$10.void
This is because $10 is most likely an anonymous class declaration which will be treated differently during compiling and subsequent obfuscation. First easy solution is of course to get rid of the anonymous declaration and declare it somewhere. Another solution would be to add the following line again to your proguard.cfg
-keepattributes EnclosingMethod
This of course will again not remove some information and will reduce your obfuscation.
I have a problem with proguard config in Android Project.
I'm using Genson to parse incoming JSON data.
It is fast and there is no need for extra configuration or deserializers, because on the Server-side there is also Genson.
Everything works fine in debug mode, but in release, with proguard it doesn't.
Unfortunately I have some error during runtime:
FATAL EXCEPTION: main
Process: com.es.mobile.meedy, PID: 16650
java.lang.UnsupportedOperationException: Couldn't find parameter at 0 from type interface com.owlike.genson.Converter , you should first locate the parameterized type, expand it and then use typeOf.
at com.owlike.genson.reflect.TypeUtil.typeOf(Unknown Source)
at com.owlike.genson.GensonBuilder.withConverters(Unknown Source)
at com.mypackage.f.k.a(Unknown Source)
at com.a.a.b.n.a(Unknown Source)
at com.a.a.i.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5086)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
It happens even if datamodel is in keep class. I tried all configrations with keep class, classmembers, etc. What else can i do?
EDIT
What else do I know:
I tried keep class with all classes in my project.
I have keep class with genson (-keep class com.owlike.genson.** { *; })
Instanceof with my class shows that it is instance of com.owlike.genson.Converter
The solution to the problem was to add -keepattributes Signature
If annotations are being used then this option should be enabled too -keepattributes *Annotation*
Also the application class being ser/de by Genson must also be provided:
-keep class com.mypackage.model.** { *; }
-keep class com.owlike.genson.*{ *; }
Add that line to your ProGuard configuration.
-keep [,modifier,...] class_specification
Specifies classes and class members (fields and methods) to be preserved as entry points to your
code. For example, in order to keep an application, you can specify
the main class along with its main method. In order to process a
library, you should specify all publicly accessible elements.
I'm running ProGuard for my release build and trying to optimize it as much as possible. The only custom rules I've added so far are Serialization and Facebook ones. I'm running my release build now and I'm getting a stack trace and what it maps back to is really throwing me off. Here's my stack trace:
java.lang.NullPointerException
E/AndroidRuntime(10842): at com.myapp.android.myapp.dh.a(Unknown Source)
E/AndroidRuntime(10842): at android.support.v4.app.Fragment.b(Unknown Source)
E/AndroidRuntime(10842): at android.support.v4.app.w.a(Unknown Source)
E/AndroidRuntime(10842): at android.support.v4.app.p.onCreatePanelMenu(Unknown Source)
E/AndroidRuntime(10842): at android.support.v7.a.g.a(Unknown Source)
E/AndroidRuntime(10842): at android.support.v7.a.m.a(Unknown Source)
E/AndroidRuntime(10842): at android.support.v7.a.g.onCreatePanelMenu(Unknown Source)
In mapping, com.myapp.android.myapp.dh.a is:
com.myapp.android.myapp.LocalFragment -> com.myapp.android.myapp.dh:
java.lang.String USER_ACCOUNT -> a
In my actual code it's this:
public static String USER_ACCOUNT = "com.myapp.android.myapp.LocalFragment.user_account";
Now this constant is used in multiple places throughout this Fragment, but it should never be null. Anyone seen a problem like this before? Does Proguard do weird stuff with statics?
Edit: This error is thrown and the app crashes basically as soon as I take the action that would load this Fragment.
EDIT AGAIN
After a bit more investigation, I was wrong about what a was. a was that Static member, but a is also a method. It's the onCreate method. I'm also seeing this error in logcat before the NPE is thrown in onCreate:
W/SupportMenuInflater(10842): Cannot instantiate class: android.support.v7.widget.SearchView
W/SupportMenuInflater(10842): java.lang.NoSuchMethodException: <init> [class android.content.Context]
W/SupportMenuInflater(10842): at java.lang.Class.getConstructorOrMethod(Class.java:472)
W/SupportMenuInflater(10842): at java.lang.Class.getConstructor(Class.java:446)
W/SupportMenuInflater(10842): at android.support.v7.internal.view.e.a(Unknown Source)
W/SupportMenuInflater(10842): at android.support.v7.internal.view.e.a(Unknown Source)
W/SupportMenuInflater(10842): at android.support.v7.internal.view.c.a(Unknown Source)
W/SupportMenuInflater(10842): at android.support.v7.internal.view.c.inflate(Unknown Source)
W/SupportMenuInflater(10842): at com.myapp.android.myapp.dh.a(Unknown Source)
You have a problem with proguard obfuscating the support libraries, or specifically, the SearchView component that you probably try to initiate in your fragment. To avoid this, you need to add few exclusions to proguard configuration file (proguard.cfg).
-keep class android.support.v7.widget.** { *; }
-keep interface android.support.v7.widget.** { *; }
This will keep all classes and interfaces inside the widget package of the support library from being obfuscated.