mercredi 30 octobre 2019

Android reflection vs proguard even with unrenamed class

I am about to give it totally up with obfuscation! I have an main app that uses multiple apks as plugins starting their services and importing their Fragments into the MainActivity. Its a bit complicated but can be done with knowledge of all the classnames and reflection.

Now comes obufcation. I knew that I needed to protect all Fragment Classes to being able to access their classes via string constants and classloader.

Lets start with StartupFragment that is internal in the Main app. Snippet of my proguard-rules.pro:

-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable,InnerClasses,Signature,*Annotation*
-keeppackagenames com.my.company.**

-keep public class * extends com.my.company.plugin.MyFragmentExtension{
    public <methods>;
    public static <fields>;
}

It looks as if the keeppackagenames and the keep extends work: I inspected the apk via: apk->unzip->dex2jar classes.dex -> jd-gui dex2jar.jar And the StartupFragment is right there inside the fully named package.

Now I wrote a little test:

 try
    {
        Fragment direct = new StartupFragment(); //always works OK!
        Log.d(TAG,TAG + " CLTEST: StartupFragment created directly");
        Fragment reflect = null;
       //Classloader taken right from the class I want to load via reflection
        ClassLoader cl = StartupFragment.class.getClassLoader(); 
       //reflection load always fails ClassNotFoundException
        Class classss= cl.loadClass(StartupFragment.class.toString()); 
        Log.d(TAG, TAG +  " CLTEST: "+StartupFragment.class.toString() +".class loaded via reflection via OWN classloader");
        reflect = (Fragment)classss.newInstance();

    }catch (ClassNotFoundException e)
    {
        Log.e(TAG,TAG + " CLTEST StartupFragment classloader has failed to find " + StartupFragment.class.getName());
        e.printStackTrace();
    }catch (Throwable e)
    {
        Log.e(TAG,TAG + " CLTEST StartupFragment classloader has failed: ",e);
        e.printStackTrace();
    }

Question now is: Why could the classloader taken from the very class it should load fail even if the class was not renamed (and even the name taken directly from the class)??

Additional info:

  • without obfuscation (minifyEnabled false) everything works fine with reflection
  • com.my.company.plugin.MyFragmentExtension is in aar package but that should not be a problem as the class was kept and not renamed?!
  • all inner classes of StartupFragment (like all those onClickListeners e.g.) got renamed and taken out of the original class (seen in the dex2jar.jar)




Aucun commentaire:

Enregistrer un commentaire