目的

Androidアプリの難読化についてのメモ
以前、3〜5年前ぐらいは Androidアプリは簡単にリバースエンジニアリングができてしまうので、難読化したほうが良い
というのを案件で一緒になったAndroidエンジニアが言っていたが、
昨今はどういう事情なのか気になったのでメモ。


というより、、 初心者Androidアプリエンジニアな自分にとっては、
難読化なんて、なにそれという感じ。
こう見えても、プライベートでAndroidアプリをリリースしているのだが。
ある日、Google Play Consoleにビルドファイルをアップロードした際
以下のようなワーニングが表示されているのに気付いた。

それで難読化設定について、調査してみた。
最後に注意点も記載。





環境

  • Android Studio Arctic Fox | 2020.3.1 Patch 3
  • classpath ‘com.android.tools.build:gradle:7.0.3’

参照サイト

developer アプリの圧縮、難読化、最適化
Code for Fun 【Android Studio】mapping.txt の作成方法
stackoverflow proguard-android-optimize.txt vs proguard-android.txt in Android build.gradle

記事内でリバースエンジニアリングを試しましたが、この記事ではやり方は書いていません。
以下のページを参照しました。
reon777 【Android】aabファイルをリバースエンジニアリングしてみた

ただ dexをjarに変換するためのツール は以下を利用しました。
dex2jar

難読化について、ドキュメントを見る

上記参照先にある、Googleのドキュメントには以下の様に書かれている。

アプリの圧縮、難読化、最適化
...

圧縮を有効にすると、アプリのクラスとメンバーの名前を短くする「難読化」と、
より積極的な戦略を適用してアプリのサイズをさらに小さくする「最適化」によるメリットも得られます。

...

Android Gradle プラグイン 3.4.0 以上を使用したプロジェクトのビルドでは、ProGuard によるコンパイル時のコード最適化が行われません。
その代わり、R8 コンパイラとの連携により、コンパイル時に以下のタスクが実行されます。

...

コードの圧縮、リソースの圧縮、難読化、最適化
アプリのリリース版をビルドする際、R8 はデフォルトで、上記のコンパイル時のタスクを自動的に実行します。

...

ただし、Android Studio を使用して新しいプロジェクトを作成する場合、圧縮、難読化、コードの最適化はデフォルトでは有効になりません。
これは、こうしたコンパイル時の最適化によってプロジェクトのビルド時間が長くなり、
保持するコードのカスタマイズが十分でない場合にバグが発生する可能性があるためです。

...
読解力が壊滅的で、初心者エンジニアの私が上記について、以下の様に考えたのと疑問点が出てきた。

  • 難読化といってもクラスやメンバー名が短縮されるだけで、暗号化とか難しいことはしていない。
  • 昔はProGuardというツールが難読化で使われていたが、今はR8というのが使われるよう。
  • R8はデフォルトで難読化を実行するよう????
  • 圧縮、難読化、コードの最適化はデフォルトでは有効ならない????

した2つが意味が分からない。デフォルトで実行されるけど、デフォルトは有効じゃない????
俺は何を言っているんだ。

そしてその下に、圧縮、難読化、最適化の有効化のやり方が書いている。






R8はデフォルトでは有効ではないけど、有効化したら自動で難読化などを実行する ということかな。


実際にaabファイルからリバースエンジニアリングしてみた

なんかGoogleのドキュメントが意味不明で信じられないので、実際に自分でリバースエンジニアリングして確かめてみた。
リバースエンジニアリングの手順は参照サイトを元に。
ココでは解説しません。

まずはbuild.gradleを特にいじっていないアプリでリバースエンジニアリング。
ちなみにこの状態だと、mapping.txtファイルは無い。/app/build/outputsフォルダ自体無い。

そうした場合

難読化せずのリバースエンジニアリング
private final void testInfo(List<? extends Test> paramList) {
    Set set1;
    Set set2 = (Set)null;
    ...
    bool = set2.contains(String.valueOf(((Test)paramList.get(b1)).VALUE));
変数は置き換わっているようだけど、関数名や一部オブジェクト名が置き換わっていなかった。






次に難読化設定をしてみた。

Googleのドキュメントにある設定方法部分は、最新化されていないよう。

設定は以下
※proguard-android-optimize.txtも部分も-optimizeを追加書き直したほうが良いみたい。

難読化設定
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

これでリバースエンジニアリングしてみた。

難読化後のリバースエンジニアリング
private final void n0(List<? extends z2.b> paramList) {
    Set set = null;
    ...
    bool = set.contains(String.valueOf(((z2.b)paramList.get(b1)).i));
難読化前のSet set1;が最適化されて無くなっていて、あと関数名やオブジェクト名が単略化されていた。

そして、/app/build/outputsフォルダができて、
mapping.txtファイルが作られていた。





とうことで、難読化設定を行う場合は、設定が必要ということと。
あとは簡単に設定できるということが分かった。

注意点

上位より、簡単に難読化できることが分かったが、注意点がある。

それはライブラリによっては不具合を起こしたり、不便があるということ。

最も重大なのはGsonだと思う。
API情報受取時にクラッシュした。(もしかしたら日本語を受け取ったときだけクラッシュするかも。。。)
proguard-rules.proに以下の設定をすればよいのかな。。ここは未確認。

proguard-rules.pro
-keep class jp.co.hoge.parser.response.** { *;}

あとFirebaseとかのクラッシュログが難読化されたクラス名で表示されるとのこと。
こちらは難読化のデメリットとして有名な項目なのだけど。

自分の環境では、難読化さらずに通常のクラス名が表示されていた。 勘違い?うまく表示される仕組みが分からない。mapping.txtも提供してないし。
GsonのエラーログがFirabaseに表示されていたので、難読化したアプリで検証したと思うのだけど。

そして最後にややこしいのが、
難読化の確認はリリースビルドの時しか確認ができないということ。
デバッグビルドでのテストで問題ないやと言って、リリースしないこと。