AndroidアプリのソースコードをProGuardで難読化

Androidアプリはデコンパイルするとソースコードを簡単に覗けてしまうので、アプリの脆弱性を突く攻撃の糸口にされたり、ソースコードを盗用されるなどが起こってしまう可能性があります。これらの対策のため、ProGuardを使ってアプリのソースコードを難読化することができます。

## 環境

* OS X EL Capitan 10.11.1
* Android SDK
    * API Level 19

## 基本設定

`project.properties`の以下の行をコメントアウトを外します。

```
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
```

### APKの作成

リリースビルドの作成で難読化されます。デバッグビルドでは難読化されません。

プロジェクトを右クリック-> Android Tools -> Export Signed Application Package

## 除外設定の流れ

デフォルトではAPK内のJarファイルを全て難読化しようとするため、そのままだとエラーになる可能性が高いです。
基本的には、以下のフローを繰り返して難読化に挑戦することになります。

*APK作成成功まで*

1. APKファイルをリリースビルド
2. エラー発生
3. コンソールからエラー内容を確認
4. `proguard-project.txt`を修正

*動作確認完了まで*

1. APKファイルをインストール
2. 基本動作を確認
3. エラー発生(logcatなどで確認)
4. `proguard-project.txt`を修正


参考までに、AWS-SDK for Androidを使っている場合は以下の設定を追加します。

```
-keep class org.apache.commons.logging.**               { *; }
-keep class com.amazonaws.services.sqs.QueueUrlHandler  { *; }
-keep class com.amazonaws.javax.xml.transform.sax.*     { public *; }
-keep class com.amazonaws.javax.xml.stream.**           { *; }
-keep class com.amazonaws.services.**.model.*Exception* { *; }
-keep class org.codehaus.**                             { *; }
-keepattributes Signature,*Annotation*
 
-dontwarn javax.xml.stream.events.**
-dontwarn org.codehaus.jackson.**
-dontwarn org.apache.commons.logging.impl.**
-dontwarn org.apache.http.conn.scheme.**
```

* [Using ProGuard with the AWS SDK for Android - AWS Developer Blog - Mobile](https://mobile.awsblog.com/post/Tx2OC71PFCTC63E/Using-ProGuard-with-the-AWS-SDK-for-Android)

## 確認

APKを解凍・デコンパイルして難読化したソースコードを確認します。

### ツールのインストール

*dex2jar*

classes.dexをjarに変換するツールです。
ダウンロードして適宜解凍・パスを通します。

[pxb1988/dex2jar](https://github.com/pxb1988/dex2jar)

*jad*

.classファイルをデコンパイルするツールです。
brewからインストールします。

```
$ brew install homebrew/binary/jad
```

### ソースコード確認

```bash
# 難読化したソース出力用のディレクトリを作成
$ rm -rf output && mkdir output

# APKを展開
$ unzip xxx.apk -d output/unzipped_apk
$ pushd output/unzipped_apk

# classes.dexをjarファイルに変換
$ dex2jar.sh classes.dex
$ popd

# classes.dexのjarファイルを展開
$ unzip output/unzipped_apk/classes_dex2jar.jar -d output/unzipped_dex

# デコンパイル
$ jad -8 -d output/decompiled_dex -s .java -r output/unzipped_dex/**/*.class

# デコンパイルしたソースコードを確認
$ ls -la output/decompiled_dex
```

## 頻出のエラー

*Activity*

Activityは難読化でエラーが発生するので除外します。

```
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}
```

*can't find referenced xxx*

ライブラリ内で宣言されているが各ロジックから参照されていないクラスに対しての警告です。不要なので除外します。

```
# -dontwarn <クラス名>
# -dontwarn <パッケージ名>.*
# 例:
-dontwarn lombok.Lombok
```

## 参考リンク

公式:

* [ProGuard](http://proguard.sourceforge.net/)

AWS:

* [Using ProGuard with the AWS SDK for Android - AWS Developer Blog - Mobile](https://mobile.awsblog.com/post/Tx2OC71PFCTC63E/Using-ProGuard-with-the-AWS-SDK-for-Android)

エラー:

* [Add Proguard for Jackson JSON Processor · Issue #19 · krschultz/android-proguard-snippets](https://github.com/krschultz/android-proguard-snippets/issues/19)
* [Android Proguard - IllegalArgumentException in Jackson's TypeReference class - Stack Overflow](http://stackoverflow.com/questions/9282721/android-proguard-illegalargumentexception-in-jacksons-typereference-class)
* [java - Using ProGuard with Android - Stack Overflow](http://stackoverflow.com/questions/11246842/using-proguard-with-android/11249755#11249755)
* [java - ProGuard obfuscation leads to ClassNotFoundException - Stack Overflow](http://stackoverflow.com/questions/26557090/proguard-obfuscation-leads-to-classnotfoundexception)