fly1tkg blog

AndroidでProguardによる難読化

AndroidアプリはJavaで書かれていますが、Javaはデコンパイルが容易です。そのため簡単にソースコードが丸見えになってしまいます。そのためにソースコード難読化がです。ProguardはJavaのソースコードを難読化するツールで、最新のADTにはAndroidで簡単に使えるようになっています。以下に現在最新のADT20で行った方法をメモしておきます。

使い方

project.propertiesのproguard.configの行をアンコメント(先頭の#を消す)します。
その後 File > Export > Export Android Applicationでリリースビルドをします。

# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

たったこれだけでソースコードの難読化ができます。

難読化の結果はprojectフォルダの中に生成されたproguardフォルダの中の4つのテキストファイルに出力されます。

  • dump.txt –> apkファイルの構成
  • mapping.txt –> 難読化されたクラスやメソッドなどの履歴
  • seeds.txt –> 難読化されていないクラスなどのリスト
  • usage.txt –> 削除されたコードのリスト

mapping.txtを開いてみるとクラス名やメソッド名がどのように変更されたかを見る事ができます。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
android.support.v4.app.ActivityCompatHoneycomb -> android.support.v4.app.a:
void invalidateOptionsMenu(android.app.Activity) -> a
android.support.v4.app.BackStackRecord -> android.support.v4.app.b:
android.support.v4.app.FragmentManagerImpl mManager -> a
android.support.v4.app.BackStackRecord$Op mHead -> b
android.support.v4.app.BackStackRecord$Op mTail -> c
int mNumOp -> d
int mEnterAnim -> e
int mExitAnim -> f
int mPopEnterAnim -> g
int mPopExitAnim -> h
int mTransition -> i
int mTransitionStyle -> j
boolean mAddToBackStack -> k
boolean mAllowAddToBackStack -> l
java.lang.String mName -> m
boolean mCommitted -> n
int mIndex -> o
int mBreadCrumbTitleRes -> p
java.lang.CharSequence mBreadCrumbTitleText -> q
int mBreadCrumbShortTitleRes -> r
java.lang.CharSequence mBreadCrumbShortTitleText -> s

このようにクラス名やメソッド名が1~2文字程度の英字に置き換わります。

Proguardの仕組み

Proguardにはコードの短縮、最適化、難読化、事前検証の4つのステップがあります。

コードの短縮や最適化のステップで、使用していないクラスやメソッドを削除したり変数の折りたたみを行ったりする事で、ソースコードの圧縮を行います。

難読化のステップではクラス名やメソッド名などを1~2文字の英数字で置き換え、難読化をさせます。

事前検証のステップではProguardでの処理で問題が無いかチェックします。

proguardの設定ファイルは2カ所に分かれておいてあって、1つは/tools/proguard/proguard-android.txt
こちらはapkにするときのproguard全体の設定が書かれています。

もう一つはprojectフォルダの中のproguard-project.txt こちらにprojectごとの設定を書きます

注意点

ProguardはピュアなJavaのコードに対してはきちんと動くようですが、Androidの様にxmlなどの静的なファイルを参照したり、いろいろしてると、誤作動で使用しているクラスやメソッドが消されてしまうことがあります。
基本的にはusage.txtと見比べながら、必要なコードが消されていないかや、mapping.txtを見てリネームしてはいけないものがリネームされていないかをチェックする必要があります。

ライブラリとしてjarを使用している場合

-libraryjar <jarのパス> のオプションをproguard-project.txtに追加します

-libraryjars ./libs/actionbarsherlock-plugin-maps-4.1.0.jar
-libraryjars ./libs/android-async-http-1.4.0.jar
-libraryjars ./libs/jsonpullparser-core-1.4.jar
-libraryjars ./libs/twitter4j-core-android-2.2.6.jar

また一般的なオープンソースのライブラリであれば、StackOverFlowとかで推奨の設定が書かれていたりします。
例えばtwitter4jであればこれ http://stackoverflow.com/questions/7721397/how-to-make-proguard-ignore-external-libraries

-keep class javax.** { *; }
-keep class org.** { *; }
-keep class twitter4j.** { *; }

-keep オプションは指定したクラスを難読化しないというオプションです

ライブラリプロジェクトを使用している場合

library projectを参照している場合は.R.classがよく消されます。
特にlibrary projectの中のdrawableなどのresourceを参照している場合です。

-keep class <パッケージ名>.R { *; }

などで消されないようにしましょう

Android NDKでJNIのメソッドを読んでいる場合

ラッパーのクラスを-keepメソッドで難読化しないようにしましょう。
nativeを読んでいるメソッドはProguard側で使用されていないメソッドとして消される場合があります

最後に

Proguardを使用したからといって、定数の中身まで難読化はされません。パスワードなどを平文でapkに含めないようにしましょう。