Android Proguard再再入門 – ② –

この記事は公開されてから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

結果がこちら

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);
}
}