Android Proguard再再入門 – ② –
仕組みを知るためにProguard後の中身をみる
今回はProguardをかけたapkをリバースエンジニアリングで戻して、
何がどうなったか、中身をみてみる。
リバースエンジニアリングの手順はこちらを参照。
AndroidのAPKをリバースエンジニアリング | Developers.IO
またメソッド数がどのように変化したかもみてみよう
Androidのメソッド数を測定する | Developers.IO
結果
ソースコードが長くなってしまったので、最初に結果から
- クラスごとごっそり消される
- クラス名、メソッド名、メンバー変数名がa,bなどに変換される
- しかし、値はそのまま
- BuildConfigもそのままみえてしまう
[メソッド数]
- 無: 16301
- 有: 6968
- 0.42倍
[アプリサイズ]
- 1212826 -> 1,2MB
- 704559 -> 0.7MB
- 0.58倍
[ビルド時間]
- 20.705 sec
- 33.155 sec
- 1.65倍
まとめ
- セキュリティ上知られてはいけないものは、ソースコード上に書かない
- メソッド数やapkが減るのでなるべく使用する
- 難読化は、名をa,bに置換される程度
次回
なんとなくProguardでエラーがなる部分がわかってきたのではないでしょうか そう、勝手にメソッドを消されちゃったり、リネームされることで、 リフレクションなどのコードでエラーなってしまうのです!
ではどうしたらいいのか。次回。
使用したコード
今回の実験で使用したコードは以下の3クラス
- MainAcitivy - UseClassをnewをする - UseClassのpublicメソッドを呼ぶ
- UseClass - アクセス修飾子、final、staticの組み合わせて、メンバー変数、メソッドを作った
- NotUseClass - UseClassのコピークラス - 他では使用されていない
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); UseClass useClass = new UseClass(); useClass.usePublic(useClass.usePublic); UseClass.useStaticPublic(UseClass.useStaticFinalPublic); } }
public class UseClass { public UseClass(){ usePrivate(usePrivate); useProtected(useProtected); useFinalDefault(useFinalDefault); } public String usePublic = "usePublic"; public static final String useStaticFinalPublic = "useStaticPublic"; private String usePrivate = "usePrivate"; protected String useProtected = "useProtected"; final String useFinalDefault = "useFinalDefault"; protected String notUseProtected = "notUseProtected"; protected static final String notUseStaticFinalProtected = "notUseStaticProtected"; private static final String notUseStaticFinalPrivate = "notUseStaticFinalPrivate"; public static String notUseStaticFinalPublic = "notUseStaticPublic"; static String notUseStaticDefault = "notUseStaticDefault"; public final String notUseFinalPublic = "notUseFinalPublic "; /* * 他のクラスでから呼ばれている */ public void usePublic(String message) { Log.d("uPublic", message); } public static void useStaticPublic(String message) { Log.d("uStaticPublic", message); } private void usePrivate(String message) { Log.d("uPrivate", message); } protected void useProtected(String message) { Log.d("uProtected", message); } final void useFinalDefault(String message) { Log.d("uFinalDefault", message); } protected void notUseProtected(String message) { Log.d("nUProtected", message); } // /* * Class内で使われてるか、他で使われていない */ protected static void notUseStaticFinalProtected(String message) { Log.d("nUFinalProtected", message); } private static void notUseStaticFinalPrivate(String message) { Log.d("nUStaticFinalPrivate", message); } public static void notUseStaticFinalPublic(String message) { Log.d("nUStaticFinalPublic", message); } static void notUseStaticDefault(String message) { Log.d("nUStaticDefault", message); } public final void notUseFinalPublic(String message) { Log.d("nUFinalPublic", message); } // public void notUseMethods(String message){ notUseFinalPublic(notUseFinalPublic); notUseProtected(notUseProtected); notUseStaticDefault(notUseStaticDefault); notUseStaticFinalPrivate(notUseStaticFinalPrivate); notUseStaticFinalProtected(notUseStaticFinalProtected); notUseStaticFinalPublic(notUseStaticFinalPublic); } }
NotUseClass.java
UseClassをコピーしたクラス。(ソースコードは割愛)
どこでも使用されていないクラス。
apkをリバースエンジニアリング
dex2jarを用いて、中身をみる
AndroidのAPKをリバースエンジニアリング | Developers.IO
結果がこちら
import android.os.Bundle; import android.support.v7.a.u; public class MainActivity extends u { protected void onCreate(Bundle paramBundle) { super.onCreate(paramBundle); setContentView(2130968601); paramBundle = new a(); paramBundle.a(paramBundle.a); a.b("useStaticPublic"); } }
import android.util.Log; public class a { public static String e = "notUseStaticPublic"; static String f = "notUseStaticDefault"; public String a = "usePublic"; protected String b = "useProtected"; final String c = "useFinalDefault"; protected String d = "notUseProtected"; public final String g = "notUseFinalPublic "; private String h = "usePrivate"; public a() { e(this.h); c(this.b); d("useFinalDefault"); } public static void b(String paramString) { Log.d("uStaticPublic", paramString); } private void e(String paramString) { Log.d("uPrivate", paramString); } public void a(String paramString) { Log.d("uPublic", paramString); } protected void c(String paramString) { Log.d("uProtected", paramString); } final void d(String paramString) { Log.d("uFinalDefault", paramString); } }