この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
仕組みを知るために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
結果がこちら
MainActivity.java
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");
}
}
a.java
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);
}
}