対象読者は?
- Androidアプリ開発者
何が書かれている?
- 難読化を実装した際の注意点
経緯:バグ調査
新規案件で、すでにAndoidアプリは別の会社が作成済み。
こちらで追加修正して、apkファイルをビルドして渡す。
で、、渡した結果。
修正したところとは全く別のところが動作してない
調査して欲しい
とのこと。
問題点:ビルドタイプの違い&難読化が影響
了解!ってことで、自分でビルドして動作確認すると動く
あれ??なんで???ビルドタイプの違い??
自分がビルドしたのは、デバックビルド。
お客さんに渡したのは、リリースビルド。
いやいや、まさかー。
う、、動かない。。。
スタックトレースを確認すると、、、NULLで落ちてる!?
しかも、中身がaとかbとかよくわからんことになってる??
よくよく調べてみると、リリースビルド時のみ難読化などを行っていましたorz
難読化の目的は大きく2つあります。
- クラス名、メソッド名などをaとかbとかに置き換えて、リバースエンジニアリングを防ぐ
- クラス名、メソッド名を短くすることでアプリ自体のサイズを小さくする
解決方法:keepルールの追加
Androidの公式ページを参照すると、難読化する時に注意しないといけないポイントがあるみたいです
難読化によりコードのさまざまな部分の名前が変更されるので、スタック トレースの検査などの特定のタスクで追加のツールが必要になります。
アプリのメソッドやクラスに予測可能な命名規則を使用している場合(リフレクションを使用している場合など)、それらのシグネチャをエントリ ポイントとして扱い、保持するコードのカスタマイズ方法で説明したように keep ルールを指定する必要があります
簡単に要約すると
- スタックトレースなどで処理を追う場合は、追加ツール使って見てね
- 予測可能な命名規則を使っている場合は、keepルールを使用してね
1つ目はわかりやすいですね。
スタックトレースで処理を追っていた時に、aとかbとか出ていたのは難読化が原因だったようです。
2つ目。今回の原因がこれでした。
予測可能な命名規則を使っている場合(リフレションなど)
「リフレクション」というのが、クラス名・メソッド名・変数名などを文字列として指定して動的に実行するための仕組みです。
メソッド名などを文字列で判定して実行するので、難読化しちゃうとそこでの判定ができなくなってしまう。文字列までは一緒に難読化してくれないですからね。。。
例)リフレクションでtest()メソッドを使うよう文字列指定→test()メソッド自体が難読化されて名称変わるので使えない。。
で、今回の問題ですが、、、リフレクション使ってましたorz
クラス自体をkeepするように変更。
追加したことで、このクラス自体が難読化されないようにすることで解決としました。
(Android 9からリフレクションを使用すること自体に制限かかってますから、リフレクション自体は使わない方が良さそうみたいですね。。)
まとめ
- リフレクションは使用しない
- 難読化するときは、難読化した影響も考慮する
- テストするときは、難読化した状態で!!
本来であれば、リフレクションを使わないようにして一緒に難読化してあげるのがベストなのでしょうが、、、そこまでする時間はありませんでした。。
難読化は今までしたことなかったので勉強になりました。
ただ、書いてて思ったのがテスト。
デバックビルドでテストしたらこの難読化問題は気づけないし、自動テストで書いてた場合ってどうなるんだろ。。。これも検知が難しいような気がしてなりません。
、、、ってことは、リリースビルドかつ実機でのテストが必須?
ふ、、不便。。orz
この辺知見ある方いましたらそっと教えてもらえると幸いですm(_ _)m