Slide 1

Slide 1 text

実践!難読化ガイド 登壇者:STORES 決済 Androidエンジニア みっちゃん

Slide 2

Slide 2 text

自己紹介 ● 名前:みっちゃん ● 経歴: ○ 22新卒でSTORES 株式会社に入社 ○ STORES 決済 Androidアプリの開発に従事 ○ Android歴は3年目くらい ○ DroidKaigiスタッフもしてます X(Twitter): 🔗@mimimi_engineer 2/101

Slide 3

Slide 3 text

本日のゴール ● 難読化ナニモワカラナイな人が、なんとなく難読化の雰囲気を 分かった気持ちになれる ● 業務で難読化関連のエラーが起きた時に、全メンバーがある程度自力 で立ち向かえる 3/101

Slide 4

Slide 4 text

● 難読化とは? ● 難読化のツール ● コラム!難読化の歴史:ProGuard、そしてR8 ● Keepルールを自由自在に操る! ● 難読化されたクラッシュレポートとの戦い方 ● よくある質問:@Keepと-keepの違い 本日のお品書き 4/101

Slide 5

Slide 5 text

● 難読化とは? ● 難読化のツール ● コラム!難読化の歴史:ProGuard、そしてR8 ● Keepルールの設定を自由自在に操る! ● 難読化されたクラッシュレポートとの戦い方 ● よくある質問:@Keepと-keepの違い 本日のお品書き 5/101

Slide 6

Slide 6 text

難読化ってなに? wikipediaさん 🔗Wikipedia_難読化 6/101

Slide 7

Slide 7 text

難読化ってなに? wikipediaさん 変数や関数名を意味のない文字列に変換するなどして コードを読みにくくするよ! wikipediaさん 🔗Wikipedia_難読化 7/101

Slide 8

Slide 8 text

難読化の目的 一般的な回答 ソースコードを読みにくくすることで 悪意のある第三者や攻撃者からプロダクトを守るため 8/101

Slide 9

Slide 9 text

難読化の目的 逆コンパイル! ハッキング! 機密情報を盗むぜ! システムを破壊するぜ! 読めん!やめる! ぴえん 難読化されたコード 9/101

Slide 10

Slide 10 text

Androidアプリ開発においてもそうなの? 10/101

Slide 11

Slide 11 text

公式ドキュメントが説明する難読化の目的 Android Developerを確認してみましょう コードを読みにくくして、悪意のある第三者からコードを守ると いうより、単に文字数を減らしてアプリサイズを小さくするとい うのが目的として大きいのかも 🔗AndroidDeveloper_コードの難読化 11/101

Slide 12

Slide 12 text

実際に難読化されたソースコードを見てみよう 確かに。めっちゃ文字数 少なくなりそう。 個人的には十分読みにくいのでソース コードを守る役割にもなってそうとも 思う。 🔗AndroidDeveloper_コードの難読化 12/101

Slide 13

Slide 13 text

どれくらいアプリサイズを小さくできるの 🔗Android Developer_Impact on runtime performance 難読化関連の設定を全て有効にすることで 実行時パフォーマンスが最大30%改善される くらいには小さくできるらしい 13/101

Slide 14

Slide 14 text

本当に難読化しないといけないのか アプリサイズが小さくなるのってそんなありがたいの? → インストール成功率への影響, Google Playにはサイズ上限がある 🔗 Play Console ヘルプ 14/101

Slide 15

Slide 15 text

結論:商用アプリ・大規模アプリは難読化しよう ● 難読化によってコードが読みにくくなり、ソースコードが攻撃者から 守られる ● AndroidDeveloperでは上記のことに言及していないが、難読化によって アプリサイズが小さくなる ● アプリサイズはAndroid開発者にとってパフォーマンスや インストール成功率の観点などから重要 15/101

Slide 16

Slide 16 text

● 難読化とは? ● 難読化のツール ● コラム!難読化の歴史:ProGuard、そしてR8 ● Keepルールの設定を自由自在に操る! ● 難読化されたクラッシュレポートとの戦い方 ● よくある質問:@Keepと-keepの違い 本日のお品書き 16/101

Slide 17

Slide 17 text

難読化を行うためのツール R8! Androidでは、R8(あーるえいと)というツールが難読化を実行してくれる ここまで難読化にだけ言及してきたが、R8は難読化以外のこともやってくれる 17/101

Slide 18

Slide 18 text

R8がやってくれる、4つのコト。 ● コードの圧縮 ● リソースの圧縮 ● 最適化 ● 難読化 18/101

Slide 19

Slide 19 text

1. コードの圧縮 ツリーシェイキングとも言われる エントリポイントからアプリのコードを検査し、到達不可能と判断した ソースコードを削除する つまり、 これ絶対実行されないし! ていうソースコードを削除してくれる! 削除 19/101

Slide 20

Slide 20 text

2. リソースの圧縮 ● 使用されていない画像やstringリソース・レイアウトxmlなどを削除する ● リソースの圧縮はコードの圧縮と連動して実行される 削除 削除 コードの圧縮によって削除されたコードの 先で参照されていたはずの不要になった リソース達も削除される 削除 20/101

Slide 21

Slide 21 text

3. 最適化 深いレベルでコードを検査して必要のないコードを削除 さらにはコードを書き直すまでして冗長なコードをとことん圧縮してくれる コ ー ド を 書 き 直 す ? 21/101

Slide 22

Slide 22 text

最適化:いらないelseを削除してくれる 22/101

Slide 23

Slide 23 text

最適化:使用箇所が限定的なメソッドをインラインで配置 calculate()からしか呼ばれてない 23/101

Slide 24

Slide 24 text

最適化:使用箇所が限定的なメソッドをインラインで配置 処理を直接配置 24/101

Slide 25

Slide 25 text

4. 難読化 先に述べた通り、クラス名やメソッド名を適当な文字に変換してくれる 25/101

Slide 26

Slide 26 text

R8の機能を有効にしよう! Android Studio 3.4 または Android Gradle プラグイン 3.4.0 以上を 使用する場合、デフォルトでR8が難読化ツールとして使われる ですが、先ほど紹介したR8の機能である コードとリソースの圧縮・最適化・難読化が有効になっている訳ではない! 💡R8を有効にするとアプリサイズは小さくできるがビルドに時間がかかってしまうので、本番用 リリースなど適切なタイミングで有効にする必要があるため 26/101

Slide 27

Slide 27 text

R8の機能を有効にしよう! Groovy build.gradle 27/101

Slide 28

Slide 28 text

難読化の設定に関わるファイル さっきのサンプルコードに次のような記述があったかと思います → 難読化の設定に関わるファイル ってなんだ?? 28/101

Slide 29

Slide 29 text

難読化の設定に関わるファイル 難読化の設定を有効化すると全てのファイルのクラス名・メソッド名が めちゃくちゃな名前に書き換えられてしまう そうすると参照先をうまく見つけられなくなって、ビルドが通らなくなる! e: Unresolved reference 29/101

Slide 30

Slide 30 text

ProGuard設定ファイル そこで、これは難読化しないでおくれ...という設定を 難読化の設定に関わるファイル(ProGurad設定ファイル)に記述する! 💡Android Studioで新しいモジュールを作成すると IDEがそのモジュールのルートディレクトリに proguard-rules.pro を自動的に作成してくれる! proguard-android-optimize.txtに関しても コンパイル時にAndroid Gradle Pluginによって自動生成される! proguard-rules.pro -keep class HogeDataClass 訳:HogeDataClassは難読化 しないでね! 30/101

Slide 31

Slide 31 text

ProGuard設定ファイルの使い分け ● proguard-android-optimize.txt ● proguard-rules.pro ● consumerProguardFiles 'proguard-consumer-rules.pro' 31/101

Slide 32

Slide 32 text

ProGuard設定ファイルの使い分け ● proguard-android-optimize.txt ○ コンパイル時にAGPによって自動生成される ○ 単にR8の機能でコードの圧縮や最適化を適用したい場合は このファイルだけを設定していればOK ● proguard-rules.pro ● consumerProguardFiles 'proguard-consumer-rules.pro' 32/101

Slide 33

Slide 33 text

ProGuard設定ファイルの使い分け ● proguard-android-optimize.txt ● proguard-rules.pro ○ モジュール作成時Android Studioがルートディレクトリ下に自動生成 ○ 特定のクラスを難読化対象から除外したいなど、難読化ルールを カスタムしたい場合にこのファイルにルールを書く ● consumerProguardFiles 'proguard-consumer-rules.pro' 33/101

Slide 34

Slide 34 text

ProGuard設定ファイルの使い分け ● proguard-android-optimize.txt ● proguard-rules.pro ● consumerProguardFiles 'proguard-consumer-rules.pro' ○ SDK開発の時に使う ○ 開発者が自分でファイルを作成する ○ SDK利用者がアプリをビルドする際に適用されてほしい難読化ルール がある場合にこのファイルにルールを書く 34/101

Slide 35

Slide 35 text

● 難読化とは? ● 難読化のツール ● コラム!難読化の歴史:ProGuard、そしてR8 ● Keepルールの設定を自由自在に操る! ● 難読化されたクラッシュレポートとの戦い方 ● よくある質問:@Keepと-keepの違い 本日のお品書き 35/101

Slide 36

Slide 36 text

Androidアプリ開発の歴史 ● 2019年くらいまで:ProGuardというツールで難読化してた ● Android Gradle Plugin 3.3.0 :R8が導入された ● Android Gradle Plugin 3.4.0:R8がデフォルトになる つまり、昔はProGuardだったけど、今はR8で難読化している 36/101

Slide 37

Slide 37 text

何が変わったの? 37/101

Slide 38

Slide 38 text

Proguardの時代 Javaバイト コード ソースコード DEXファイル コンパイル ProGuard (難読化) D8 (DEX化) Kotlin/Javaファイル をAndroid環境で 実行可能な形式に 変換圧縮したもの 38/101

Slide 39

Slide 39 text

新時代:R8の時代 Javaバイト コード ソースコード DEXファイル コンパイル R8 (難読化・DEX化) Kotlin/Javaファイル をAndroid環境で 実行可能な形式に 変換圧縮したもの R8によって難読化・最適化する機能 とDEX化する機能が統合された! ステップ数が減ることでビルド時間短縮につながった!! 💡詳しくはDroidKaigi 2019 SatoShunさんの発表:🔗R8/ProGuard 徹底比較 を参照してください 39/101

Slide 40

Slide 40 text

● 難読化とは? ● 難読化のツール ● コラム!難読化の歴史:ProGuard、そしてR8 ● Keepルールの設定を自由自在に操る! ● 難読化されたクラッシュレポートとの戦い方 ● よくある質問:@Keepと-keepの違い 本日のお品書き 40/101

Slide 41

Slide 41 text

Keepルールの設定を自由自在に操る! ProGuard設定ファイルを使って難読化を回避するルールをカスタムできますが、 ProGuard特有の文法や構文があり、慣れるまでは読むのも書くのもむずかしい。 41/101 proguard-rules.pro -keep class HogeDataClass 訳:HogeDataClassは難読化 しないでね!

Slide 42

Slide 42 text

Keepルールの設定を自由自在に操る! Keepルールの設定を自由自在に操るための5つのノウハウ ● テンプレートを知ろう! ● 基本的な-keepの種類を知ろう! ● よく出てくる記号の意味を知ろう! ● 原理原則に基づいて立ち向かおう! ● 情報収集できる場所を知ろう! 42/101

Slide 43

Slide 43 text

1. テンプレートを知ろう! 例えばGreetクラスのhelloメソッドを難読化対象から外したいとする 43/101

Slide 44

Slide 44 text

1. テンプレートを知ろう! そのような場合は次のようなKeepルールを書けば良い 🔗ProGuard Playground 44/101

Slide 45

Slide 45 text

これをもうちょっと抽象化すると・・・ めっちゃ大体こういう↑感じの文法です。 45/101 1. テンプレートを知ろう!

Slide 46

Slide 46 text

見比べてみる 46/101 1. テンプレートを知ろう!

Slide 47

Slide 47 text

関数以外にもクラスやインタフェース、Companion objectなど 場合によって難読化対象から外したいものがたくさんあると思います。 全部説明すると時間がないので、公式が提示している網羅的なテンプレートを置いときます↓ 🔗ProGuardドキュメント _Configuration_Usage_ClassSpecifications 文法がわからなくなった時は テンプレートを確認しよう! 47/101 1. テンプレートを知ろう!

Slide 48

Slide 48 text

2. 基本的な-keepの種類を知ろう! -keepで難読化を回避するが、-keepにも種類が色々ある 🔗ProGuardドキュメント_Overview of Keep Options 48/101

Slide 49

Slide 49 text

もっと分かりやすいのを見ましょう 🔗Qiita_Proguard設定のメモ_keepオプション_@boohbah (Jumpei Yamamoto) 49/101 2. 基本的な-keepの種類を知ろう!

Slide 50

Slide 50 text

3. よく出てくる記号(ワイルドカード)の意味を知ろう! ここでは、なんとなく読める&書けるようになるための大体の意味を紹介します 💡クラスに付与するかフィールドやメソッドに付与するかで若干意味合いや守備範囲が変わったりするので 詳細は🔗ProGuardドキュメント_Class Specificationsのwild cardのパートを見て下さい 50/101

Slide 51

Slide 51 text

記号 (ワイルドカー ド) 説明 使い方の例 ←の結果 難読化回避されるものの例 ? 任意の一文字にマッチする -keep class com.example.Test? com.example.Test1 com.example.TestA * 任意の一単語にマッチする -keep class com.example.* com.example.HogeClass com.example.FooClass ** 任意の一部にマッチする かつ、パッケージセパレーターも含む -keep class com.example.** com.example.HogeClass com.example.subpackage.FugaClass … 任意の数の任意の型の引数にマッチ -keep class com.example. * { public void hogeMethod(...); } hogeMethod() hogeMethod(a: Int) hogeMethod(a: String, b: Int) すべてのコンストラクタにマッチ -keep class MyClass { @javax.inject.Inject (...); } MyClassにある全てのコンストラクタ <field> すべてのフィールドにマッチ -keep class MyClass { public <fields>; } MyClassにある全てのpublicなフィール ド すべてのメソッドにマッチ -keep class MyClass { public ; } MyClassにある全てのpublicなメソッド 51/101

Slide 52

Slide 52 text

記号 (ワイルドカー ド) 説明 使い方の例 ←の結果 難読化回避されるものの例 ? 任意の一文字にマッチする -keep class com.example.Test? com.example.Test1 com.example.Test2 * 任意の一単語にマッチする -keep class com.example.* com.example.HogeClass com.example.FooClass ** 任意の一部にマッチする かつ、パッケージセパレーターも含む -keep class com.example.** com.example.HogeClass com.example.subpackage.FugaClass … 任意の数の任意の型の引数にマッチ -keep class com.example. * { public void hogeMethod(...); } hogeMethod() hogeMethod(a: Int) hogeMethod(a: String, b: Int) すべてのコンストラクタにマッチ -keep class MyClass { @javax.inject.Inject (...); } MyClassにある全てのコンストラクタ <field> すべてのフィールドにマッチ -keep class MyClass { public <fields>; } MyClassにある全てのpublicなフィール ド すべてのメソッドにマッチ -keep class MyClass { public ; } MyClassにある全てのpublicなメソッド 52/101

Slide 53

Slide 53 text

記号 (ワイルドカー ド) 説明 使い方の例 ←の結果 難読化回避されるものの例 ? 任意の一文字にマッチする -keep class com.example.Test? com.example.Test1 com.example.Test2 * 任意の一単語にマッチする -keep class com.example.* com.example.HogeClass com.example.FooClass ** 任意の一単語にマッチする かつ、パッケージセパレーターも含む -keep class com.example.** com.example.HogeClass com.example.subpackage.FugaClass … 任意の数の任意の型の引数にマッチ -keep class com.example. * { public void hogeMethod(...); } hogeMethod() hogeMethod(a: Int) hogeMethod(a: String, b: Int) すべてのコンストラクタにマッチ -keep class MyClass { @javax.inject.Inject (...); } MyClassにある全てのコンストラクタ <field> すべてのフィールドにマッチ -keep class MyClass { public <fields>; } MyClassにある全てのpublicなフィール ド すべてのメソッドにマッチ -keep class MyClass { public ; } MyClassにある全てのpublicなメソッド 53/101

Slide 54

Slide 54 text

記号 (ワイルドカー ド) 説明 使い方の例 ←の結果 難読化回避されるものの例 ? 任意の一文字にマッチする -keep class com.example.Test? com.example.Test1 com.example.Test2 * 任意の一単語にマッチする -keep class com.example.* com.example.HogeClass com.example.FooClass ** 任意の一単語にマッチする かつ、パッケージセパレーターも含む -keep class com.example.** com.example.HogeClass com.example.subpackage.FugaClass … 任意の数の任意の型の引数にマッチ -keep class com.example. * { public void hogeMethod(...); } hogeMethod() hogeMethod(a: Int) hogeMethod(a: String, b: Int) すべてのコンストラクタにマッチ -keep class MyClass { @javax.inject.Inject (...); } MyClassにある全てのコンストラクタ <field> すべてのフィールドにマッチ -keep class MyClass { public <fields>; } MyClassにある全てのpublicなフィール ド すべてのメソッドにマッチ -keep class MyClass { public ; } MyClassにある全てのpublicなメソッド 54/101

Slide 55

Slide 55 text

記号 (ワイルドカー ド) 説明 使い方の例 ←の結果 難読化回避されるものの例 ? 任意の一文字にマッチする -keep class com.example.Test? com.example.Test1 com.example.Test2 * 任意の一単語にマッチする -keep class com.example.* com.example.HogeClass com.example.FooClass ** 任意の一単語にマッチする かつ、パッケージセパレーターも含む -keep class com.example.** com.example.HogeClass com.example.subpackage.FugaClass … 任意の数の任意の型の引数にマッチ -keep class com.example. * { public void hogeMethod(...); } hogeMethod() hogeMethod(a: Int) hogeMethod(a: String, b: Int) すべてのコンストラクタにマッチ -keep class MyClass { @javax.inject.Inject (...); } MyClassにある全てのコンストラクタ <field> すべてのフィールドにマッチ -keep class MyClass { public <fields>; } MyClassにある全てのpublicなフィール ド すべてのメソッドにマッチ -keep class MyClass { public ; } MyClassにある全てのpublicなメソッド 55/101

Slide 56

Slide 56 text

記号 (ワイルドカー ド) 説明 使い方の例 ←の結果 難読化回避されるものの例 ? 任意の一文字にマッチする -keep class com.example.Test? com.example.Test1 com.example.Test2 * 任意の一単語にマッチする -keep class com.example.* com.example.HogeClass com.example.FooClass ** 任意の一単語にマッチする かつ、パッケージセパレーターも含む -keep class com.example.** com.example.HogeClass com.example.subpackage.FugaClass … 任意の数の任意の型の引数にマッチ -keep class com.example. * { public void hogeMethod(...); } hogeMethod() hogeMethod(a: Int) hogeMethod(a: String, b: Int) すべてのコンストラクタにマッチ -keep class MyClass { @javax.inject.Inject (...); } MyClassにある全てのコンストラクタ <field> すべてのフィールドにマッチ -keep class MyClass { public <fields>; } MyClassにある全てのpublicなフィール ド すべてのメソッドにマッチ -keep class MyClass { public ; } MyClassにある全てのpublicなメソッド 56/101

Slide 57

Slide 57 text

記号 (ワイルドカー ド) 説明 使い方の例 ←の結果 難読化回避されるものの例 ? 任意の一文字にマッチする -keep class com.example.Test? com.example.Test1 com.example.Test2 * 任意の一単語にマッチする -keep class com.example.* com.example.HogeClass com.example.FooClass ** 任意の一単語にマッチする かつ、パッケージセパレーターも含む -keep class com.example.** com.example.HogeClass com.example.subpackage.FugaClass … 任意の数の任意の型の引数にマッチ -keep class com.example. * { public void hogeMethod(...); } hogeMethod() hogeMethod(a: Int) hogeMethod(a: String, b: Int) すべてのコンストラクタにマッチ -keep class MyClass { @javax.inject.Inject (...); } MyClassにある全てのコンストラクタ <field> すべてのフィールドにマッチ -keep class MyClass { public <fields>; } MyClassにある全てのpublicなフィール ド すべてのメソッドにマッチ -keep class MyClass { public ; } MyClassにある全てのpublicなメソッド 57/10 1

Slide 58

Slide 58 text

4. 原理原則に基づいて立ち向かおう! R8はJavaバイトコード上で動作することを覚えておきましょう その原理原則を忘れてしまうと、どうやってKeepルールを書いていいのかわからなくなることがあります Javaバイト コード ソースコード DEXファイル コンパイル R8 (難読化・DEX化) Kotlin/Javaファイル をAndroid環境で 実行可能な形式に 変換圧縮したもの 58/101

Slide 59

Slide 59 text

59/101 4. 原理原則に基づいて立ち向かおう! 例えばクラス外で宣言された showMessage()を 難読化から回避したい場合

Slide 60

Slide 60 text

60/101 全てのKeepルールにクラス名は必須だけど クラス内にないんだが?

Slide 61

Slide 61 text

Javaバイトコードをみる! このような場合は内部的に ファイル名 + Kt(接尾語) という名前のクラスファイル が生成される 61/101

Slide 62

Slide 62 text

JavaバイトコードからKeepルールを考える 難読化が回避されている!! 62/101

Slide 63

Slide 63 text

JavaバイトコードからKeepルールを考える 63/101 わからなくなったら原理原則に立ち戻り Javaバイトコードから考えよう!!

Slide 64

Slide 64 text

コラム!Android Studioでデコンパイルしよっ そうはいっても、 Javaバイトコードを確認するのだるいよ...と思った方もいるでしょう Android Studioの機能で簡単にKotlinコードをバイトコードに変換し、 バイトコードをデコンパイルすることができます 64/101

Slide 65

Slide 65 text

コラム!Android Studioでデコンパイルしよっ 65/10 1

Slide 66

Slide 66 text

コラム!Android Studioでデコンパイルしよっ 66/10 1

Slide 67

Slide 67 text

コラム!Android Studioでデコンパイルしよっ 67/10 1

Slide 68

Slide 68 text

コラム!Android Studioでデコンパイルしよっ 68/10 1

Slide 69

Slide 69 text

コラム!Android Studioでデコンパイルしよっ 69/10 1

Slide 70

Slide 70 text

コラム!Android Studioでデコンパイルしよっ デコンパイル後の Javaコードが簡単に 生成される! 70/101

Slide 71

Slide 71 text

5. 情報収集できる場所を知ろう! ● やはり公式ドキュメント、特にUsageのパートは便利です ○ 🔗ProGuard manual Configuration_Usage ● GUARDSQUARE社のブログ ○ 🔗Keep Rules in the Age of Kotlin ● PlaygroundもKeepルールを楽して考える上でとても便利 ○ 🔗ProGuard Playground 71/101

Slide 72

Slide 72 text

● PlayGroundも難読化ルールを実践的に勉強する上でとても便利 ○ 🔗ProGuard Playground 72/101 5. 情報収集できる場所を知ろう! ⚠ 仕事で開発しているアプリを アップロードする場合は、自社のセ キュリティポリシーと、サービスの セキュリティポリシーをご確認の上 ご利用お願いします

Slide 73

Slide 73 text

ProGuard Playgroundがいかに便利か 難読化を回避したい メソッドやクラスを選択 Keepルールを提案してくれる \ 便利すぎてヤバイ / ボタンぽちでルールを 適用してくれる 73/101

Slide 74

Slide 74 text

ProGuard Playgroundがいかに便利か 書き込んだKeepルールによって どこが難読化回避されるのか アイコンで教えてくれる \ さすがに神 / 74/101

Slide 75

Slide 75 text

● 難読化とは? ● 難読化のツール ● コラム!難読化の歴史:ProGuard、そしてR8 ● Keepルールの設定を自由自在に操る! ● 難読化されたクラッシュレポートとの戦い方 ● よくある質問:@Keepと-keepの違い 本日のお品書き 75/101

Slide 76

Slide 76 text

難読化されたクラッシュレポートとの戦い方 難読化でビルドが通らなくなってしまった原因の場所さえ分かれば あとは先の章で話した通りProGuardのドキュメントを見ながらKeepルールを 追加し、難読化対象から外してあげればいいだけ! 逆にいうと、原因に辿り着くまでの探索が難しい・・・ 76/101

Slide 77

Slide 77 text

どうして難しい? R8で処理された後のソースコードは 圧縮やコードの最適化を経て行番号が変更されていたり、 難読化によってクラスやメソッドの名前が変更されていたりする →スタックトレースがソースコードと正確に一致せず、原因が追いづらい!! e: /~~/HogeActivity.kt: Unresolved reference: a どれ?! 77/101

Slide 78

Slide 78 text

難読化されたクラッシュレポートとの戦い方 この章では難読化が原因でビルドが通らなくなってしまった時の 原因箇所の特定方法について解説します! 78/101

Slide 79

Slide 79 text

原因を調べる3つの方法 ● mappingファイルを活用する ● retraceコマンドを活用する ● Firebase Crashlyticsを確認する 79/101

Slide 80

Slide 80 text

1. mappingファイルを活用する R8を有効にしてアプリをビルドすると /build/outputs/mapping// 配下に mapping.txt が生成される ただの対応表 80/101

Slide 81

Slide 81 text

2. retraceコマンドを活用する mapping.txtはただの対応表なのでこれを頼りに スタックトレース読み解くのはちょっとしんどい mappingファイルを使って 難読化前の状態のスタックトレースを表示する方法もあります! 81/101

Slide 82

Slide 82 text

retraceコマンドとは? 難読化される前の情報を復元することをリトレースと言う アプリケーションのスタックトレースをリトレースし、原因の場所を特定する! 82/101

Slide 83

Slide 83 text

retraceコマンドを活用する リトレースに必要な情報を保持しておくために、 以下のルールをproguard-rules.proファイルに追加 💡LineNumberTable: メソッド内の位置情報を保持する, スタックトレースを出力する際に行番号として表示する 💡SourceFile: 全てのjava実行環境(ランタイム)で一貫して行番号情報を出力するために必要 retraceコマンドを叩く 難読化前の命名や行番号でスタックトレースがコマンドラインに表示される 🔗AndroidDeveloper_R8_retrace 83/101

Slide 84

Slide 84 text

3. Firebase Crashlyticsを確認する Firebase Crashlyticsを使っている場合は、 Crashlytics Gradle プラグインがビルドプロセス中に 自動的にmappingファイルをアップロードし、それを元に アプリのスタックトレースの難読化を解除し 人が読める形式のコードにしてクラッシュレポートを出力してくれる! 💡デフォルトでそうなってるので、回避したい場合はbuild.gradleでmappingFileUploadEnabled=falseにする 🔗Firebase_Crashlytics ダッシュボードで読み取り可能なクラッシュレポートを取得する 84/101

Slide 85

Slide 85 text

● 難読化とは? ● 難読化のツール ● コラム!難読化の歴史:ProGuard、そしてR8 ● Keepルールの設定を自由自在に操る! ● 難読化でビルドが通らなくなった時の戦い方 ● よくある質問:@Keepと-keepの違い 本日のお品書き 85/101

Slide 86

Slide 86 text

@Keepアノテーションとは Hoge.kt const val HOGE = “hoge” proguard-rules.pro -keep class Hoge { public static String HOGE; } 定数HOGEを難読化 回避したい場合 proguard-rules.pro に-keepをする 86/101

Slide 87

Slide 87 text

@Keepアノテーションとは Hoge.kt const val HOGE = “hoge” proguard-rules.pro -keep class Hoge { public static String HOGE; } Hoge.kt const val HOGE = “hoge” @Keep 定数HOGEを難読化 回避したい場合 難読化を回避したいとこ ろに直接@Keepをつける ことでも回避できる 87/101

Slide 88

Slide 88 text

じゃあ全部@Keepすればよくない? 88/101

Slide 89

Slide 89 text

結論:ライブラリを配布する場合に注意が必要! 🔗Android Developer_Keep 89/101

Slide 90

Slide 90 text

なぜライブラリコードで@Keepは使わない方が良い? 90/101 ライブラリのコードが難読化されるポイントに着眼してみる 1. ライブラリ開発者がリリースの ためにビルドするとき 2. ライブラリを含んだアプリが ビルドされるとき // 公開API val brand : EmoneyBrand 決済ライブラリ ビルド 決済ライブラリ レジ アプリ ビルド

Slide 91

Slide 91 text

なぜライブラリコードで@Keepは使わない方が良い? 91/101 ライブラリのコードが難読化されるポイントは2つ 1. ライブラリ開発者がリリースの ためにビルドするとき 2. ライブラリを含んだアプリが ビルドされるとき // 公開API val brand : EmoneyBrand 決済ライブラリ ビルド 決済ライブラリ レジ アプリ ビルド 開発者に使ってもらうために 難読化せずに配布したい 開発者がアプリをビルドする際 にはもう難読化されていい

Slide 92

Slide 92 text

@Keepの定義を確認してみる 🔗Android Developer_Keep 🔗Kotlinドキュメント_AnnotationRetention バイナリ(ビルド後のライブラリ)でも アノテーションの効力が保持されるよという意味 92/101

Slide 93

Slide 93 text

なぜライブラリコードで@Keepは使わない方が良い? 93/101 ライブラリのコードが難読化されるポイントは2つ 1. ライブラリ開発者がリリースの ためにビルドするとき 2. ライブラリを含んだアプリが ビルドされるとき // 公開API @Keep val brand : EmoneyBrand 決済ライブラリ ビルド 決済ライブラリ レジ アプリ ビルド @Keepを使って 難読化回避しちゃうと・・・ ビルド後のライブラリにも @Keepの影響が残ってしまう!! ❌難読化・最適化

Slide 94

Slide 94 text

なぜライブラリコードで@Keepは使わない方が良い? 94/101 このケースを回避するため公式はProGuard設定ファイルでのルール指定を推奨してる 1. ライブラリ開発者がリリースの ためにビルドするとき 2. ライブラリを含んだアプリが ビルドされるとき // 公開API val brand : EmoneyBrand 決済ライブラリ ビルド 決済ライブラリ ProGuard設定ファイルを使って 難読化回避していれば・・・ 1のタイミングのProGuard設定ファイル は2のタイミングでは参照されない! proguard -keep … { brand } ⭕難読化・最適化 レジ アプリ ビルド

Slide 95

Slide 95 text

まとめ ● 難読化とは、クラス名やメソッド名を短くして アプリサイズを小さくすること ● R8というツールで、難読化以外にも最適化やリソースの圧縮を実行する 95/101

Slide 96

Slide 96 text

まとめ ● 難読化によってビルドが通らなくなった場合は、 ProGuard設定ファイルにKeepルールを書いて難読化回避しよう ● R8は、Kotlinコードではなく、Javaバイトコード上で実行されることを 意識してKeepルールを考えよう ● @Keepでも難読化回避は可能であるが、ライブラリ開発の場合はやめよう 96/101

Slide 97

Slide 97 text

参考文献 ● AndroidDeveloper_アプリの圧縮、難読化、最適化 https://developer.android.com/build/shrink-code?hl=ja ● AndroidDeveloper_コードの難読化 https://developer.android.com/build/shrink-code?hl=ja#obfuscate ● AndroidDeveloper_Keep https://developer.android.com/reference/androidx/annotation/Keep ● Qiita_Androidアプリの圧縮、難読化、最適化【R8】 https://qiita.com/toroncho-good/items/cce0e660caba6a5d4191 97/101

Slide 98

Slide 98 text

参考文献 98/101 ● Qiita_Proguard設定のメモ_keepオプション_@boohbah (Jumpei Yamamoto) https://qiita.com/boohbah/items/7372b29637d28e6d671c#keep%E3%82%AA%E3%83%97% E3%82%B7%E3%83%A7%E3%83%B3 ● Keep Rules in the Age of Kotlin https://www.guardsquare.com/blog/keep-rules-in-the-age-of-kotlin ● R8/ProGuard 徹底比較 https://satoshun.github.io/2019/02/droidkaigi-2019/

Slide 99

Slide 99 text

参考文献 ● Android Gradle プラグイン 3.4.0(2019 年 4 月) https://developer.android.com/build/releases/past-releases/agp-3-4-0-release-notes?hl=ja ● ProGuard manual_Usage https://www.guardsquare.com/manual/configuration/usage ● AndroidDeveloper_D8 https://developer.android.com/tools/d8 99/101

Slide 100

Slide 100 text

参考文献 ● AndroidDeveloper_Development considerations for library modules https://developer.android.com/studio/projects/android-library#Considerations ● Kotlinドキュメント_AnnotationRetention https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.annotation/-annotation-retention/ ● AndroidDeveloper_R8_retrace https://developer.android.com/tools/retrace?hl=ja 100/101

Slide 101

Slide 101 text

おしまい 101/101