Slide 1

Slide 1 text

Flutterと難読化 FlutterKaigi2024 @ B Dash 11/22 14:30-15:10 Kazuki Chigita (@chigichan24)

Slide 2

Slide 2 text

自己紹介 名前: Kazuki Chigita (@chigichan24) お仕事: Androidアプリ開発者 Flutter関連でのアウトプット: flutter_blue へ のcontribution、日本語での記事執筆など 最近の興味: Impeller https://www.slideshare.net/slideshow/flutterble/125792150 https://qiita.com/chigichan24/items/89cb686e880f0274ed1c

Slide 3

Slide 3 text

アイスブレーク

Slide 4

Slide 4 text

アイスブレーク class A extends B { const A({super.c,}); @override X ut(Vx hk, E mb) { final l = Ml.t(hk);final wh = mb.pc(g); final q = mb.pc(vv).y?.rp((e) => e is Nf && wh.q.lt(e.id),) ?? [];return Et( mp: Wk(k: [Uu.tgf(lrc: Nb(l.tp),), Tq(xo: const Ci.zz(16), sr: So.oi(cn: [for (final x in q) Yz( ie: x as Nf, cz: () async => Wsx(bb: x.id).di(hk),) ,],),),],),);} }

Slide 5

Slide 5 text

アイスブレーク class A extends B { const A({super.c,}); @override X ut(Vx hk, E mb) { final l = Ml.t(hk);final wh = mb.pc(g); final q = mb.pc(vv).y?.rp((e) => e is Nf && wh.q.lt(e.id),) ?? [];return Et( mp: Wk(k: [Uu.tgf(lrc: Nb(l.tp),), Tq(xo: const Ci.zz(16), sr: So.oi(cn: [for (final x in q) Yz( ie: x as Nf, cz: () async => Wsx(bb: x.id).di(hk),) ,],),),],),);} } Q. FlutterKaigiアプリのどの画面?

Slide 6

Slide 6 text

アイスブレーク class A extends B { const A({super.c,}); @override X ut(Vx hk, E mb) { final l = Ml.t(hk);final wh = mb.pc(g); final q = mb.pc(vv).y?.rp((e) => e is Nf && wh.q.lt(e.id),) ?? [];return Et( mp: Wk(k: [Uu.tgf(lrc: Nb(l.tp),), Tq(xo: const Ci.zz(16), sr: So.oi(cn: [for (final x in q) Yz( ie: x as Nf, cz: () async => Wsx(bb: x.id).di(hk),) ,],),),],),);} } Q. FlutterKaigiアプリのどの画面?

Slide 7

Slide 7 text

セッションのゴール 1. 難読化の仕組みと目的を理解する (Chapter 1) 2. 難読化に関して実践的なトラブルシューティングが できるようになる (Chapter 1, 4) 3. Flutterでの難読化の動作原理や限界を理解する (Chapter 2, 3)

Slide 8

Slide 8 text

アジェンダ 1. 難読化とは 2. 難読化の仕組み 3. 複数のプラットフォームで動作する仕組み 4. トラブルシューティングtips

Slide 9

Slide 9 text

おことわり ● 以下の環境での確認 ○ Flutter 3.24.3 ○ Dart 3.5.3

Slide 10

Slide 10 text

1. 難読化とは

Slide 11

Slide 11 text

1. 難読化とは ● 難読化 (Obfuscate) ○ コードの難読化とは、人間が理解しにくくなるように アプリバイナリを修正するプロセスのこと。

Slide 12

Slide 12 text

1. 難読化とは ● 難読化 (Obfuscate) ○ コードの難読化とは、人間が理解しにくくなるように アプリバイナリを修正するプロセスのこと。 Q. 開発者が他の開発者のことを思って わかりやすい変数名・クラス名・メソッド名にしたのに、 わざわざ理解しにくくなるような変更をするの?

Slide 13

Slide 13 text

● 難読化 (Obfuscate) ○ コードの難読化とは、人間が理解しにくくなるように アプリバイナリを修正するプロセスのこと。 A-1. 攻撃者のリバースエンジニアリングを困難にするため A-2. バイナリサイズを小さくするため 1. 難読化とは

Slide 14

Slide 14 text

1. 難読化とは ● よくある誤解 ○ 難読化とは暗号化である ■ データやリソースが暗号化されるわけでない ■ 例えばシークレットキーなどを平文で持ってしまっては いけない ○ リバースエンジニアリングを完全に防ぐことができる ■ クラス・変数名からのリバースエンジニアリングは できないが、ロジックはわかる

Slide 15

Slide 15 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される

Slide 16

Slide 16 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される

Slide 17

Slide 17 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される 難読化前のコード class _MyHomePageState extends State { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } }

Slide 18

Slide 18 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _MyHomePageState extends State { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } }

Slide 19

Slide 19 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _MyHomePageState extends State { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } } Obfuscation map

Slide 20

Slide 20 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _MyHomePageState extends State { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } } Obfuscation map _MyHomePageState → _aU

Slide 21

Slide 21 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _MyHomePageState extends State { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } } Obfuscation map _MyHomePageState → _aU

Slide 22

Slide 22 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _aU extends State { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } } Obfuscation map _MyHomePageState → _aU

Slide 23

Slide 23 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _aU extends State { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } } Obfuscation map _MyHomePageState → _aU

Slide 24

Slide 24 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _aU extends State { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } } Obfuscation map _MyHomePageState → _aU State → Nq

Slide 25

Slide 25 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _aU extends Nq { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } } Obfuscation map _MyHomePageState → _aU State → Nq

Slide 26

Slide 26 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _aU extends Nq { int _counter = 0; void _incrementCounter() { setState( () { _counter++; }); } } Obfuscation map _MyHomePageState → _aU State → Nq …

Slide 27

Slide 27 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される class _aU extends Nq { int _gic = 0; void _hic() { ISa( () { _gic++; }); } } Obfuscation map _MyHomePageState → _aU State → Nq MyHomePage → ZT _counter → _gic _incrementCounter → _hic setState → ISa

Slide 28

Slide 28 text

1. 難読化とは ● Flutterでの難読化 ○ release buildでは基本的に難読化される 難読化後のコード class _aU extends Nq { int _gic = 0; void _hic() { ISa( () { _gic++; }); } }

Slide 29

Slide 29 text

1. 難読化とは ● Flutterでの難読化 ○ flutter build コマンドで --obfuscate オプションを使う。 ○ flutter build ipa --help In a release build, this flag removes identifiers and replaces them with randomized values for the purposes of source code obfuscation. This flag must always be combined with "--split-debug-info" option, the mapping between the values and the original identifiers is stored in the symbol map created in the specified directory. For an app built with this flag, the "flutter symbolize" command with the right program symbol file is required to obtain a human readable stack trace.

Slide 30

Slide 30 text

1. 難読化とは ● Flutterでの難読化 ○ flutter build コマンドで --obfuscate オプションを使う。 ○ flutter build ipa --help In a release build, this flag removes identifiers and replaces them with randomized values for the purposes of source code obfuscation. This flag must always be combined with "--split-debug-info" option, the mapping between the values and the original identifiers is stored in the symbol map created in the specified directory. For an app built with this flag, the "flutter symbolize" command with the right program symbol file is required to obtain a human readable stack trace. 単体では使えない

Slide 31

Slide 31 text

1. 難読化とは ● Flutterでの難読化 ○ flutter build apk --split-debug-info = /path/to/symbol In a release build, this flag reduces application size by storing Dart program symbols in a separate file on the host rather than in the application. The value of the flag should be a directory where program symbol files can be stored for later use. These symbol files contain the information needed to symbolize Dart stack traces. For an app built with this flag, the "flutter symbolize" command with the right program symbolfile is required to obtain a human readable stack trace. This flag cannot be combined with "--analyze-size".

Slide 32

Slide 32 text

1. 難読化とは ● Flutterでの難読化 ○ flutter build apk --split-debug-info = /path/to/symbol In a release build, this flag reduces application size by storing Dart program symbols in a separate file on the host rather than in the application. The value of the flag should be a directory where program symbol files can be stored for later use. These symbol files contain the information needed to symbolize Dart stack traces. For an app built with this flag, the "flutter symbolize" command with the right program symbolfile is required to obtain a human readable stack trace. This flag cannot be combined with "--analyze-size".

Slide 33

Slide 33 text

1. 難読化とは ● flutter build apk --obfuscate --split-debug-info

Slide 34

Slide 34 text

1. 難読化とは ● flutter build apk --obfuscate --split-debug-info 難読化前のコード 難読化後のコード symbols file

Slide 35

Slide 35 text

1. 難読化とは ● 難読化されたコードを戻すときは symbols file を用いる 難読化前のコード 難読化後のコード symbols file

Slide 36

Slide 36 text

1. 難読化とは ● 難読化されたコードを戻すときは symbols file を用いる ● flutter symbolize -i /path/to/log -d /path/to/symbols-file 難読化前のコード 難読化後のコード symbols file

Slide 37

Slide 37 text

1. 難読化とは ● 難読化されたコードを戻すときは symbols file を用いる ● flutter symbolize -i /path/to/log -d /path/to/symbols-file 難読化前のコード 難読化後のコード symbols file Production のスタックトレース解析には必須

Slide 38

Slide 38 text

1. 難読化とは ● どういった難読化がされたかを確認することもできる。 難読化前のコード 難読化後のコード symbols file mapping.json

Slide 39

Slide 39 text

1. 難読化とは ● どういった難読化がされたかを確認することもできる。 難読化前のコード 難読化後のコード symbols file obfuscation-map ["_initialLifecycleStateAccessed@1506558 9","_DCa@15065589","untransformedEndP osition","gHb","_color@92443363","_DYa @92443363","crossAxisAlignment","PWa", "_lastPosition@196518508","_xHb@19651 8508","__ConstMap&_HashVMImmutableBa se&MapMixin&_HashBase&_OperatorEquals AndCanonicalHashCode&_LinkedHashMapMi xin&_UnmodifiableMapMixin&_ImmutableLi nkedHashMapMixin","_Lc", … ]

Slide 40

Slide 40 text

1. 難読化とは ● どういった難読化がされたかを確認することもできる。 難読化前のコード 難読化後のコード symbols file obfuscation-map ["_initialLifecycleStateAccessed@1506558 9","_DCa@15065589","untransformedEndP osition","gHb","_color@92443363","_DYa @92443363","crossAxisAlignment","PWa", "_lastPosition@196518508","_xHb@19651 8508","__ConstMap&_HashVMImmutableBa se&MapMixin&_HashBase&_OperatorEquals AndCanonicalHashCode&_LinkedHashMapMi xin&_UnmodifiableMapMixin&_ImmutableLi nkedHashMapMixin","_Lc", … ]

Slide 41

Slide 41 text

1. 難読化とは ● 例えば Sentry では ○ CI のためのプラグインが symbols のアップロードを サポート ○ > 難読化が解除されたログの状態で、(Slack等で)Sentryの エラー通知を受け入れることができる。 ○ ● Crashlyticsにも同様のものがある https://github.com/getsentry/sentry-dart-plugin

Slide 42

Slide 42 text

1. 難読化とは ● コマンド集 ○ リリースビルド ■ flutter build apk ○ debug infoを同時に吐く ■ flutter build apk --obfuscate \ --split-debug-info=/path/to/symbols ○ Obfuscation mapを同時に吐く ■ flutter build apk --obfuscate \ --split-debug-info=/path/to/symbols \ --extra-gen-snapshot-options=--save-obfuscation-map= /path/to/map.json

Slide 43

Slide 43 text

アジェンダ 1. 難読化とは 2. 難読化の仕組み 3. 複数のプラットフォームで動作する仕組み 4. トラブルシューティングtips

Slide 44

Slide 44 text

2. 難読化の仕組み

Slide 45

Slide 45 text

2. 難読化の仕組み ● オプションの説明を思い出す。 ○ In a release build, this flag removes identifiers and replaces them with randomized values for the purposes of source code obfuscation. ● どうやって、ランダムな文字列がマップされているのだろう?

Slide 46

Slide 46 text

2. 難読化の仕組み ● アプリを構成する要素 ○ Dartで記述されたコード ○ 各プラットフォーム向けのコード ○ 画像等のアセット

Slide 47

Slide 47 text

2. 難読化の仕組み ● アプリを構成する要素 ○ Dartで記述されたコード ○ 各プラットフォーム向けのコード ○ 画像等のアセット どのようなステップを経て難読化が完了するか dart-lang/sdkを追ってみよう!

Slide 48

Slide 48 text

2. 難読化の仕組み ● 本題に入る前に DartVMについて ○ DartVM とは実行環境だけでなく、Dartの実行のために必要 な様々な環境を提供する

Slide 49

Slide 49 text

2. 難読化の仕組み ● 本題に入る前に DartVMについて ○ DartVM とは実行環境だけでなく、Dartの実行のために必要 な様々な環境を提供する ○ 2つのモードがある JIT mode AOT mode

Slide 50

Slide 50 text

2. 難読化の仕組み ● JIT (Just in Time) pipeline mode ○ 開発時のhotreload を支える仕組み ○ コード実行時にコンパイルをする ○ デバッグモードで主に使用される ● AOT (Ahead of Time) pipeline mode ○ コンパイルのあるステップで難読化をサポートする ○ コード実行前にコンパイルをする ○ リリースモードで主に使用される https://mrale.ph/dartvm/

Slide 51

Slide 51 text

2. 難読化の仕組み ● AOT pipeline mode での難読化処理 ○ dart-lang/sdk の precompiler.h / precompiler.cc が 担っている ○ その中でも処理は Obfuscator クラスに集約されている https://github.com/dart-lang/sdk/blob/main/runtime/vm/compiler /aot/precompiler.cc#L3345-L3414

Slide 52

Slide 52 text

2. 難読化の仕組み ● 大まかなステップ 1. 難読化が 必要なものを 集める 2. ルールに 則って rename作業 をする 3. mapを 保存する

Slide 53

Slide 53 text

2. 難読化の仕組み ● 大まかなステップ 1. 難読化が 必要なものを 集める 2. ルールに 則って rename作業 をする 3. mapを 保存する https://github.com/dart-lang/sdk/blob/main/runtime/vm/compiler/aot/prec ompiler.cc#L3986-L4082

Slide 54

Slide 54 text

void Obfuscator::ObfuscationState::NextName() { // We apply the following rules: // inc(a) = b, ... , inc(z) = A, ..., inc(Z) = a & carry. for (intptr_t i = 0;; i++) { const char digit = name_[i]; if (digit == '\0') { name_[i] = 'a'; } else if (digit < 'Z') { name_[i]++; } else if (digit == 'Z') { name_[i] = 'a'; continue; // Carry. } else if (digit < 'z') { name_[i]++; } else { name_[i] = 'A'; } break; } } 本質パートはこれだけ https://github.com/dart-lang/sdk/blo b/main/runtime/vm/compiler/aot/prec ompiler.cc#L3986-L4007

Slide 55

Slide 55 text

StringPtr Obfuscator::ObfuscationState::NewAtomicRename( bool should_be_private) { do { NextName(); renamed_ = Symbols::NewFormatted( thread_, "%s%s", should_be_private ? "_" : "", name_ ); // Must check if our generated name clashes with something that will // have an identity renaming. } while (renames_.GetOrNull(renamed_) == renamed_.ptr()); return renamed_.ptr(); } private のアンダースコアは、 難読化後も残す https://github.com/dart-lang/sdk/blo b/main/runtime/vm/compiler/aot/prec ompiler.cc#L4009-L4019

Slide 56

Slide 56 text

StringPtr Obfuscator::ObfuscationState::BuildRename( const String& name, bool atomic ) { // Omit code... // Handle non-obfuscation case if (atomic) { return NewAtomicRename(name.CharAt(0) == '_'); } // Omit code... // Parse `name` and split into atomic component. // After that call `BuildName` recursively. } private かどうかは先頭が ‘_’ どうかしかみていない https://github.com/dart-lang/sdk/blob/main/runtime/vm/co mpiler/aot/precompiler.cc#L4021-L4082

Slide 57

Slide 57 text

StringPtr Obfuscator::ObfuscationState::BuildRename( const String& name, bool atomic ) { // Omit code... // Handle non-obfuscation case if (atomic) { return NewAtomicRename(name.CharAt(0) == '_'); } // Omit code... // Parse `name` and split into atomic component. // After that call `BuildName` recursively. } private かどうかは先頭が ‘_’ どうかしかみていない 再帰的に処理

Slide 58

Slide 58 text

アジェンダ 1. 難読化とは 2. 難読化の仕組み 3. 複数のプラットフォームで動作する仕組み 4. トラブルシューティングtips

Slide 59

Slide 59 text

3. 複数のプラットフォームで動作する仕組み

Slide 60

Slide 60 text

3. 複数のプラットフォームで動作する仕組み ● アプリを構成する要素 ○ Dartで記述されたコード ○ 各プラットフォーム向けのコード ○ 画像等のアセット

Slide 61

Slide 61 text

3. 複数のプラットフォームで動作する仕組み ● アプリを構成する要素 ○ Dartで記述されたコード ○ 各プラットフォーム向けのコード ○ 画像等のアセット

Slide 62

Slide 62 text

3. 複数のプラットフォームで動作する仕組み ● アプリを構成する要素 ○ Dartで記述されたコード ○ 各プラットフォーム向けのコード ○ 画像等のアセット 各プラットフォーム固有の実装を使用する!

Slide 63

Slide 63 text

3. 複数のプラットフォームで動作する仕組み ● Androidでの例 ○ flutter build apk --obfuscate --split-debug-info = /path ○ tips: command parser等は dart で書かれているよ ○ build_apk.dart や flutter.groovy が処理を担っている。

Slide 64

Slide 64 text

3. 複数のプラットフォームで動作する仕組み ● Androidでの例 ○ flutter build apk --obfuscate --split-debug-info = /path ○ tips: command parser等は dart で書かれているよ ○ build_apk.dart や flutter.groovy が処理を担っている。

Slide 65

Slide 65 text

3. 複数のプラットフォームで動作する仕組み ● Androidでの例 ○ flutter build apk --obfuscate --split-debug-info = /path ○ tips: command parser等は dart で書かれているよ ○ build_apk.dart や flutter.groovy が処理を担っている。 release { minifyEnabled(true) shirinkResources(isBuildAsApp(project)) proguardFiles( project.android.getDefaultProguardFile("proguard-android.txt"), flutterProguardRules, "proguard-rules.pro" ) }

Slide 66

Slide 66 text

3. 複数のプラットフォームで動作する仕組み ● Androidでの例 ○ flutter build apk --obfuscate --split-debug-info = /path ○ tips: command parser等は dart で書かれているよ ○ build_apk.dart や flutter.groovy が処理を担っている。 release { minifyEnabled(true) shirinkResources(isBuildAsApp(project)) proguardFiles( project.android.getDefaultProguardFile("proguard-android.txt"), flutterProguardRules, "proguard-rules.pro" ) } R8 (Androidの世界の難読化) も 適用している!

Slide 67

Slide 67 text

3. 複数のプラットフォームで動作する仕組み Dartコード

Slide 68

Slide 68 text

3. 複数のプラットフォームで動作する仕組み obfuscation Dartコード shrinking

Slide 69

Slide 69 text

3. 複数のプラットフォームで動作する仕組み obfuscation Dartコード shrinking flutter runtime Dart VM (AOT compile)

Slide 70

Slide 70 text

3. 複数のプラットフォームで動作する仕組み obfuscation Dartコード shrinking flutter runtime Dart VM (AOT compile) 難読化された ネイティブライブラリ libapp.so

Slide 71

Slide 71 text

3. 複数のプラットフォームで動作する仕組み obfuscation Dartコード shrinking flutter runtime Dart VM (AOT compile) libapp.so 難読化された ネイティブライブラリ debug-info

Slide 72

Slide 72 text

3. 複数のプラットフォームで動作する仕組み libapp.so Android向け のコード リソース ファイル

Slide 73

Slide 73 text

3. 複数のプラットフォームで動作する仕組み Android向け のコード リソース ファイル R8の適用 libapp.so

Slide 74

Slide 74 text

3. 複数のプラットフォームで動作する仕組み Android向け のコード リソース ファイル R8の適用 libapp.so obfuscation shrinking

Slide 75

Slide 75 text

3. 複数のプラットフォームで動作する仕組み Android向け のコード リソース ファイル R8の適用 libapp.so obfuscation shrinking apk

Slide 76

Slide 76 text

3. 複数のプラットフォームで動作する仕組み Android向け のコード リソース ファイル R8の適用 libapp.so obfuscation shrinking apk mapping.txt

Slide 77

Slide 77 text

3. 複数のプラットフォームで動作する仕組み Android向け のコード リソース ファイル R8の適用 libapp.so obfuscation shrinking apk mapping.txt

Slide 78

Slide 78 text

3. 複数のプラットフォームで動作する仕組み Dartコード

Slide 79

Slide 79 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode)

Slide 80

Slide 80 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime

Slide 81

Slide 81 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime obfuscation shrinking

Slide 82

Slide 82 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime obfuscation shrinking libapp.so

Slide 83

Slide 83 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime obfuscation shrinking libapp.so Androidの コード リソース ファイル

Slide 84

Slide 84 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime obfuscation shrinking libapp.so Androidの コード リソース ファイル R8の適用

Slide 85

Slide 85 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime obfuscation shrinking libapp.so Androidの コード リソース ファイル R8の適用 obfuscation shrinking apk

Slide 86

Slide 86 text

3. 複数のプラットフォームで動作する仕組み Androidの コード リソース ファイル R8の適用 libapp.so obfuscation shrinking apk mapping.txt Dartコード flutter runtime DartVM (AOT mode) obfuscation shrinking debug-info 2 phaseの難読化が 行われている

Slide 87

Slide 87 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime obfuscation shrinking libapp.so Androidの コード リソース ファイル R8の適用 obfuscation shrinking apk Androidでのパターン

Slide 88

Slide 88 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime obfuscation shrinking libapp.so Androidの コード リソース ファイル R8の適用 obfuscation shrinking apk Androidでのパターン その他のプラットフォーム

Slide 89

Slide 89 text

3. 複数のプラットフォームで動作する仕組み Dartコード DartVM (AOT mode) flutter runtime obfuscation shrinking libapp.so Androidの コード リソース ファイル R8の適用 obfuscation shrinking apk Androidでのパターン その他のプラットフォーム 各プラットフォームに 詳細実装を移譲している

Slide 90

Slide 90 text

3. 複数のプラットフォームで動作する仕組み ● Flutterでの難読化 aar linux ios windows apk app bundle ios- framework ipa macos macos- framework

Slide 91

Slide 91 text

3. 複数のプラットフォームで動作する仕組み ● Flutterでの難読化 aar linux ios windows apk app bundle ios- framework ipa macos macos- framework Webはどこにいった?

Slide 92

Slide 92 text

3. 複数のプラットフォームで動作する仕組み ● webがTargetの場合の動作 ○ 難読化 (Obfuscation)ではなく、ミニファイ(Minification) される Q. 難読化とミニファイの違いはなに? なぜ、難読化のステップがwebだけ特殊化されているの?

Slide 93

Slide 93 text

3. 複数のプラットフォームで動作する仕組み ● webがTargetの場合の動作 ○ 難読化 (Obfuscation)ではなく、ミニファイ(Minification) される A. ターゲットがwebの場合のみDartVMはwebに特化した 異なるアプローチが取られているから

Slide 94

Slide 94 text

3. 複数のプラットフォームで動作する仕組み ● dart2js は native DartVMとは異なる仕組みで動作している ● これまで説明したアプローチは使用されていない ● wasm サポートによって、これから変わっていくかも...

Slide 95

Slide 95 text

3. 複数のプラットフォームで動作する仕組み ● まとめ ○ 難読化は大きく2つのパートからなる ■ 1. Dart のコード ■ 2. それぞれのプラットフォームのコード・リソース ○ Flutterではこれらを包括的に扱かっている ■ flutter symbolize で基本的にはすべて解決する ■ 一部はプラットフォームの難読化解除を使用する ○ DartVMの仕組みに依存するため、 ターゲットがwebかどうかで大きく動作が異なる

Slide 96

Slide 96 text

アジェンダ 1. 難読化とは 2. 難読化の仕組み 3. 複数のプラットフォームで動作する仕組み 4. トラブルシューティングtips

Slide 97

Slide 97 text

4. トラブルシューティングtips

Slide 98

Slide 98 text

4. トラブルシューティングtips ● Q. 一部のクラスや変数名については難読化を適用したくない (R8のkeep ruleのようなことをしたい) ● A. @pragma("vm:entry-point") を使おう。 ○ Class / Procedure / Field に適用可能 ○ 例えば、getter だけ難読化を適用しないということも可能 @pragma("vm:entry-point") class Foo @pragma("vm:entry-point", "get") int foo;

Slide 99

Slide 99 text

4. トラブルシューティングtips ● Q. --split-debug-info と --obfuscate の差分がわからない ● A. --obfuscate は単体では使うことができない ○ --split-debug-info はdebug symbols をバイナリに含めない ためのオプション ○ アプリサイズの削減にも使われるtips

Slide 100

Slide 100 text

4. トラブルシューティングtips ● Q. runtimeで型を比較するようなケースで失敗する ● A. 難読化されてるから、runtimeだと命名が違う ○ FooBar だったものが Xz などになってしまう ○ ログを送るケースなどでも気をつけないと、難読化されたロ グを送ってしまうことになるので注意が必要

Slide 101

Slide 101 text

まとめ (セッションのゴールへのアンサー) 1. 難読化の仕組みと目的を理解する (Chapter 1) → リバースエンジニアリングへの対策、 rename のマップを保持する。symbols ファイルを使う 2. 難読化に関して実践的なトラブルシューティングが できるようになる (Chapter 1, 4) → 様々な flutter command を使用する 3. Flutterでの難読化の動作原理や限界を理解する (Chapter 2, 3) → Dartの難読化とプラットフォームの難読化のステップがある web のプラットフォームは特殊化されている

Slide 102

Slide 102 text

Thank you ● 細かな質問は Ask the speaker にて! @chigichan24

Slide 103

Slide 103 text

参考資料 (1) 1. https://www.slideshare.net/slideshow/flutterble/125792150 2. https://qiita.com/chigichan24/items/89cb686e880f0274ed1c 3. https://docs.flutter.dev/deployment/obfuscate 4. https://docs.flutter.dev/perf/app-size 5. https://docs.flutter.dev/deployment/android 6. https://docs.flutter.dev/deployment/ios 7. https://docs.flutter.dev/deployment/web 8. https://github.com/flutter/flutter 9. https://github.com/flutter/engine 10. https://developer.android.com/build/shrink-code 11. https://pub.dev/documentation/native_stack_traces/latest/index.html 12. https://pub.dev/documentation/meta/latest/index.html 13. https://wiki.dwarfstd.org/ 14. https://docs.flutter.dev/resources/faq 15. https://docs.sentry.io/platforms/flutter/upload-debug/ 16. https://github.com/getsentry/sentry-dart-plugin 17. https://zenn.dev/tsuruo/articles/48909d22d49ffe

Slide 104

Slide 104 text

参考資料 (2) 18. https://developer.android.com/build/shrink-code 19. https://github.com/dart-lang/sdk 20. https://mrale.ph/dartvm/ 21. https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pra gma.md 22. https://speakerdeck.com/mitchan/shi-jian-nan-du-hua-gaido 23. https://docs.flutter.dev/deployment/android