このチェックリストは、アプリケーションやライブラリを PreEmptive Protection™ DashO™ で保護する際に、考慮すべき事項を確認するための 1 つの場所を提供します。 このチェックリストは随時、また、新しいバージョンの DashO に更新する都度、見直す必要があります。
開発手法
次に挙げるものは必須ではありませんが、備えているものとします。
- ソース管理システム
- ビルド アーティファクト リポジトリ(公開可能およびプライベートのビルド成果物を格納する機能)
- 開発者システムやインテグレーター システムとは異なる、継続的な統合環境
ソース ファイル
次のファイルをソース ファイルとして扱い、ソース管理システムで保持する必要があります。
-
プロジェクト構成ファイル(
some-project.dox
) - DashO Project Wizard を使用した場合は、それによって生成されたすべてのファイル(
.gitignore
、gradle.properties
、Ant ファイルをサポートする.war
プロジェクトなど) -
増分難読化を使用する場合のみ:入力として、名前変更の割り当てファイルと文字列の暗号化割り当てファイル(
some-project-input.map
とsome-project-input-se.map
、標準モードのみ)
これらのファイルは、ソフトウェアと共に進化する必要があります。
ビルド成果物
次のファイルは、プライベート ビルド成果物として扱う必要があります(または、プライベート ビルド成果物として扱われるアーカイブ ファイルに収集することができます)。
- 名前変更の割り当てファイル(標準モード プロジェクトの場合は
some-project.map
、Android モード プロジェクトの場合は R8 によるbuild/.../mapping.txt
出力) - 文字列の暗号化割り当てファイル(
some-project-se.map
、標準モードのみ) - DashO のコンソール出力のログ(これは、ビルドの警告やエラーを調査するときに役立ちます。Android モード プロジェクトの場合は、
build/outputs/logs
下に自動的に記録されます) -
DashO レポート(
some-project-report.txt
とsome-project-mapreport.txt
、標準モードのみ)
上記のファイルの一部は、実際に適用した保護や、今後のために使用可能にする必要のある保護(監査など)の記録を保持するために重要です。 名前変更の割り当てファイルを使用して、保護されたアプリケーションのスタック トレースをデコードすることができます。 名前変更の割り当てファイルと名前の変更レポートを使用すれば、名前の変更を効率的に元に戻すことができるため、秘密を守る必要があります。
プロジェクトの機密性に応じて、異なる方法でこれらのファイルを扱うことが必要になる場合があります。 たとえば、ビルド ログは、内部に公開して保護の検証に使用することがあります。一方、名前変更の割り当てファイルと名前の変更レポートは、保護を元に戻すためにそれらを使用する可能性があるため、特定の担当者しかアクセスできないようにすることがあります。
保護されていないアプリケーション バイナリまたはライブラリ バイナリを保持している場合、それらはプライベートのままにする必要があります。 保護されたアプリケーション バイナリまたはライブラリ バイナリを構成するファイルはすべて、公開可能なビルド成果物になります。
どのバイナリがどのログ ファイルまたは名前変更の割り当てファイルに対応するのかで混乱が生じないよう、ビルドごとに個別のバージョンを持つことは重要です。 たとえば、割り当てファイルはビルド間で大幅に異なることがあるため(増分難読化を使用していない場合)、スタック トレースのデコードに間違った割り当てファイルを使用すると、正しくない結果になります。
一時ファイル
保持する必要のないファイルには、次のものがあります。
- DashO 自動入力管理のキャッシュ ファイル(
.dasho
/、Android モードのみ) - DashO 関連のすべての一時ファイルまたは中間ファイル(
build/tmp
や Gradle ビルド用のbuild/intermediates
下のファイルを含む)
ビルド統合
継続的な統合ビルドのステップとして、DashO の保護を含める必要があります。 その際、次のことを確認してください。
-
ビルドはクリーンである。 以前のビルド結果を誤って使用することがないよう、ビルドの前に、既存のバイナリや中間ファイルはすべて削除されている。
-
プロジェクトはリリース モードでビルドされている。
標準モード プロジェクトの場合、これは
javac
に-g
オプションを指定してコンパイルしないだけで簡単にできます。 DashO は、既定ではデバッグ情報を除去しますが、これは、先頭にデバッグ情報が置かれないようにします。Android モード プロジェクトの場合は、リリース ビルド タイプでビルドすることを意味します。 少なくとも、これにより、リリース署名付きのアプリケーションに DashO が確実に適用されます。
-
ビルド サーバーおよび開発用コンピューターには、最新バージョンの DashO がインストールされている。 あるいは、少なくとも、お持ちのライセンスで付与されている最新のバージョンである。 弊社は、保護機能について常に改善を行っています。
-
ビルド サーバーではビルド ライセンスを使用している。 一般リリース用のソフトウェアを保護するときに使用できるのは、DashO ビルド ライセンスのみです。 これは、コマンド ライン出力を調べれば確認できます。
-
DashO はエラーなしで実行され完了する必要がある。 DashO の保護ステップがゼロ以外の終了コードで終了した場合、ビルドは失敗する必要があります。 これは Android モード プロジェクトに対して自動的に行われます。 ビルド処理で、DashO ビルド出力を一般的なビルド ログ ファイルに保持するか、または別のビルド ログとして保持する必要があります。 詳細なログを有効にすることを検討してください。
-
DashO によって出力される警告がないかビルドを監視するようにする。 通常、DashO の警告は、構成を調整するかコードを変更して対処する必要があります。 対処できない警告がいくつかあります(たとえば、暫定的なモジュール サポートが有効になっているときに出力される警告など)。 これらのリストを保持することは、新しい警告が無視されていないことを確認するために有用かもしれません。 新しいバージョンの DashO では、既存のプロジェクトでこれまで知られていなかった問題を示す可能性がある状態について、警告を追加することがあります。 新しい警告は、DashO 構成に対応する更新をしないでソフトウェアに変更を加えた場合に出力されることがあります。
-
署名が期待どおりに行われたことを確認する。 DashO の改ざんチェックは、アプリへの署名(Android モードおよび標準モードの APK ビルド)および jar 署名(その他の標準モード プロジェクト)と連携して機能します。 DashO 構成で指定された証明書は、エンド ユーザーが受け取るバイナリの署名に使用されたものと一致している必要があります。 これは、Android 以外のプロジェクトの場合は簡単ですが、Android プロジェクトでこれを行う方法の詳細については、Android 署名を参照してください。
-
DashO は実行時に、カスタマー フィードバック プログラムを介して、機能の利用状況およびサマリー プロジェクトのデータを弊社のサーバーに送信することができる。 これは既定では有効になっています。 お客様およびお客様の会社に差し支えなければ、この機能を有効にしておいてください。 これは、新機能および既存の機能を開発するために役立っています。
製品の構成
プロジェクトに合うように DashO 構成を調整することは重要です。
-
Android プロジェクトをビルドする場合は、Android 用の保護の強化に記載されている各事項を行います。
-
Android 以外のプロジェクトをビルドする場合は、主要な機能である名前の変更、制御フロー、文字列の暗号化、および除去を必ず有効にします。 また、改ざんチェックを追加し、できれば改ざんのレスポンスを使用してチェックと操作を切り離します。 これは、コードが変更されることから守ります。 さらに、デバッグ チェックを追加し、できればデバッグのレスポンスを使用してチェックと操作を切り離します。 これは、コードが調査されることから守ります。調査は、チェックを削除してコードを変更するための最初のステップです。 このように、チェックと難読化機能が連携して動作することでコードを保護します。
-
プロジェクトがライブラリである場合は、API が正しく保持されるようにします。 API 内のパブリック クラスおよびメソッドは、エントリ ポイントとしてマークされます。 ライブラリのすべての機能(たとえば、文字列定数など)を実行するテスト アプリケーションを用意する必要があります。 このテスト アプリケーションは、保護されたライブラリを使ってコンパイルも実行もできる必要があります。
-
文字列の暗号化を使用する場合は、除去も有効にすることが重要です。 詳細については、文字列の暗号化を参照してください。
保護の確認
配置した保護オプションが期待どおりに目的を果たしているかどうかを確認することも重要です。 保護を確認するには、信頼できるローカル コンピューター(たとえば、リモート サービス以外)でツールを使用します。
Android プロジェクトの場合は、unzip
、Apktool(DashO tools/
)、および dex2jar(DashO tools/
)を使用して .apk
または .aar
を調べることができます。 Android 以外のプロジェクトの場合は、unzip
や jar
を使用して .jar
または .war
を調べることができます。 クラス ファイルを取得したら、javap
または strings
を使用してクラス ファイルの側面を調べることができます。 また、最適な逆コンパイラを使用してクラス ファイルを調べることもお勧めします。
-
名前の変更:保護されたライブラリを解凍すると、ほとんどのクラスの名前が変更されていることがわかります。 クラス ファイル内では、ほとんどのメソッド名とフィールド名が変更されていることがわかります。 特に機密性の高い名前のメソッドがある場合は、それらの名前が変更されていることを確認してください。 これらの名前は、名前変更の割り当てファイルに表示される名前と一致しているはずですが、バイナリを直接確認することが、確実にする最善の方法です。
Android プロジェクトの場合は、
unzip
または Apktool を使用してclasses.dex
ファイルを取得したら、dex2jar
を使用してこのファイルを.jar
ファイルに変換し、次にunzip
またはjar
を使用して、変換された.jar
ファイルを解凍します。 -
制御フロー:最善のチェック方法は、逆コンパイラでクラス ファイルを調べることです。 BytecodeViewer という逆コンパイル ツールを使用すると、一度に複数の逆コンパイラ(FernFlower、Procyon、CFR など)を試すことができます。 逆コンパイラがスタック トレースを表示する(逆コンパイルしようとして「クラッシュ」した)か、見たところでは解釈できない不要コードを表示すれば、制御フローは成功しています。
制御フローの難読化の手法は、存在するコードを変更することです。 そのため、非常に小さなメソッド(いくつかのバイトコード命令しかないメソッドなど)に対して、制御フローが非常に効果的であると期待しないでください。 通常、小さなメソッドには作業することが多くありませんし、いずれにしても、保護する知的財産はあまりありません。
-
文字列の暗号化:
javap
を使用してクラス ファイルを見ると、文字列が暗号化されていることが明確に示されます。 特に機密性の高い文字列については、grep
のようなツールを使用して、その文字列がいずれのクラス ファイルにも表示されないことを確認してください。 Java コンパイラは、静的な最終定数の文字列を行内で展開するため、この確認は重要です。 除去の有効化により、静的な最終文字列フィールドが削除されるようになります。 -
リソースの暗号化:
unzip
または任意のアーカイブ ツールを使用して、.apk
ファイルを開きます。 JPEG、MPEG など、ほとんどのファイル形式では、保護されたファイルを通常のアプリケーションで開くことはできません。 さらに、そのようなファイルをテキスト エディターなどで開くと、一見ランダムに見える一連のバイトが表示されます。 特定のファイルは暗号化されるが、それ以外は暗号化されない理由について質問がある場合は、GUI の[Preview Rule]および[Preview All]機能を使用すると、 パターン(正規表現など)がファイル名に一致する方法をよりよく理解できます。 -
チェックは、保護されたアプリケーションをさまざまな条件下で実行することにより確認できます。
-
除去:保護されたライブラリ内に存在するメソッドやクラスが少なくなっていることを確認します。 レポートを参照して削除された項目を確かめ、そのクラス、メソッド、またはフィールドが、保護されたプロジェクト バイナリ内に存在していないことを確認します。
-
Premark(ウォーターマーク):
premark
を使って、ウォーターマークが存在することを確認します。
保護されたプロジェクトのテスト
保護されたアプリケーションに対していくつかのテストを実施する必要があるかもしれませんが、毎回リリース前には、保護されたアプリケーションが機能テストを受けることは非常に重要です。 難読化アルゴリズムにはランダム性が本来備わっているため、アプリケーションが保護されるたびに出力は異なります。 非常にまれであることを期待しますが、バグにより、同じアプリケーションの後続の 2 つの保護が異なる動作をする可能性があります。
保護されたアプリケーションの定期処理パフォーマンス テストをお勧めします。 これにより、アプリケーションに加えた変更が原因で、アプリケーションの保護を最初に構成したときには存在しなかったパフォーマンス問題が生じることを回避できます。 プロジェクトの構成に重要な変更を加えた場合には、パフォーマンス テストを実施することをお勧めします。
以下のセクションでは、主要な機能を説明するとともに、機能ごとに必要に応じて機能とパフォーマンスに関する考慮事項について説明します。
名前の変更(機能)
名前の変更による難読化は、難読化の最も一般的な形態であり、高い有効性がありますが、シンボルの名前が変更され、そのシンボルへの参照の名前は変更されない場合、アプリケーションの機能を壊す可能性があります。 ほとんどの場合、DashO は、シンプルなリフレクションやマニフェスト ファイルなどにある名前ベースの参照を自動的に識別し、参照の名前を自動的に変更することができます。 しかし、より複雑な参照は静的に分析することができないため、名前を変更できません。 DashO は、そのような参照を識別し、適切なシンボルを名前変更の対象から除外するよう試みますが、これをすべてのシナリオで行うことは不可能です。 そのため、名前変更が適用された後、機能テストのためのプロジェクト スケジュールを立てることは重要です。 また、どれくらい積極的にシンボルの名前を変更するかを決定することも重要です。 既定では、DashO は比較的安全な設定を使用します。
名前変更による保護を強化するための最初のステップは、必ずエントリ ポイントを指定することです。 エントリ ポイントが指定されていない場合、DashO はプロジェクトをライブラリのように扱い、パブリック メソッドなどの名前を変更しません。
アプリケーションが比較的簡単な方法でリフレクションを使用している場合は、リフレクション クラスを名前変更するのも妥当かもしれません。
制御フロー(パフォーマンス)
ほとんどの場合、制御フローの難読化は低リスクです。 DashO は現在、3 種類の制御フローの難読化、つまり、ブロックの入れ替え、Try/Catch による難読化、ブロック分割を提供しています。 3 種類すべて、既定で有効になっています。
ただし、コードのパフォーマンスを要求される領域では、制御フローの難読化はパフォーマンスを低下させる可能性があるため、それに関して懸念がある場合は、パフォーマンスをテストするか、またはコードのパフォーマンスを要求される領域を制御フローの難読化の対象から除外してください。
一部の制御フローの難読化は、Dalvik Android デバイス(Android KitKat 以前)では正しく動作しない可能性があります。 Android アプリケーションを Dalvik デバイスで実行したい場合は、[Dalvik compatibility]を有効にすることを考慮する必要があります。
文字列の暗号化(パフォーマンス)
文字列の暗号化による難読化は、比較的安全な設定で既定で有効になっています。 文字列の暗号化は、文字列へのアクセス方法を変更するため、特に、タイトなループで文字列にアクセスする場合には、パフォーマンスに影響を及ぼします。 文字列の暗号化によって生じるパフォーマンスの変化を確認するために、アプリケーションのパフォーマンスをテストする必要があります。
Java コンパイラは文字列定数の使用を行内で展開するため、文字列の暗号化を使用するときは、使用されていないフィールドの除去を有効にすることが重要です。
パフォーマンスの低下と引き換えに保護を強化させるために、文字列の暗号化「レベル」を上げることができます。 既定値の 2
は、保護と速度の安全なバランスを提供します。
特に機密性の高い文字列については、カスタムの文字列暗号化を使用することができます。 これを使用すると、文字列を暗号化および復号するための独自の jar を提供できます。 カスタムの文字列暗号化は、既定ではどこにも適用されないのに対し、文字列の暗号化は、既定であらゆる場所に適用されます。 カスタムの文字列暗号化を使用する場合には、文字列定数が定義されているクラスとメソッドだけでなく、文字列定数が参照されるクラスとメソッドも対象として選択されることに注意してください。
リソースの暗号化(機能、パフォーマンス)
リソースの暗号化を使用すると、Android の Asset および Raw リソースを暗号化することができます。 DashO Gradle プラグイン(Android 用)は、Gradle ビルド処理にリソースを暗号化するためのステップを追加します。そのため、この機能は標準モードの APK プロジェクトでは利用できません。 リソースの暗号化は既定では無効になっています。 使用するには、有効にして、暗号化する必要のある Asset および Raw リソースを構成します。
DashO は、呼び出しが使用される前に、リソースにアクセスする呼び出しをリソースを復号するためのコードでラップする必要があります。 Android リソースはさまざまな方法でアクセスできます。 DashO は、一般的なアクセスのモードをサポートしていますが、それらをすべてサポートしているわけではありません。 したがって、DashO がすべての呼び出しをラップすることができたのかを確認するために、リソースの暗号化が適用された後のアプリケーションで機能テストを行うことは重要です。
実行時の Asset および Raw リソースの復号には、無視できないほどの処理能力を必要とします。 したがって、リソースの暗号化を有効にした後、特に、サポート対象のデバイスのうち、搭載されている CPU が遅いかコア数が少ないデバイス上で、アプリケーションのパフォーマンス テストを行うことも重要です。 アプリケーション内のリソースの量とサイズに応じて、重要度の低い資産を対象から除外する必要があるかもしれません。
チェック(機能)
DashO のすべてのチェックは、アプリケーションのライフサイクル内の特定の時刻および場所、具体的に言うと、チェックを差し込むよう DashO を構成したあらゆるところで実行されます。 通常、チェックを差し込むのに適しているのは、アプリケーションのスタートアップかその近くはもちろんのこと、アプリケーションのライフサイクル全体のほかの場所、特に、コードの機密性が高い領域の周辺も適しています。
DashO のすべてのチェックは、チェックがトリガーされたときに構成できる、動作の共通セットを共有しています。 それぞれの動作には、あらかじめの考慮がいくらか必要です。
最初に、チェックは、トリガーされたときのカスタム動作を有効にするために、アプリケーション内のメソッドを呼び出す(またはフィールドを設定する)ことができます。 カスタム動作は、アプリケーションの動作を変更したり、サード パーティ製のアナリティクス プラットフォームを使用したりするために使用されます。 カスタム動作を使用するには、アプリケーション コードを変更または追加する必要があります。 したがって、これは開発者がコードを変更できる場合のみのオプションです。
次に、DashO は、定義済みの操作(アプリケーションの終了など)を自動的に実行するコードを差し込むことができます。 チェックによってトリガーされる動作(組み込みまたはカスタム)に関する重要な考慮事項は、動作の妥当性です。 たとえば、デバッグ チェックがトリガーされた場合は、アプリケーションを終了するか、またはアプリケーションの機能セットを制限することが適切です。 けれども、本番アプリケーションにデバッガーをアタッチできることが正当なシナリオが存在する可能性があるため、すべてのアプリケーション データをワイプすることは、おそらく適切ではありません。
使用されていないコードの除去(機能)
DashO は、アプリケーションから使用されていないコードを除去することもできます。 これは標準モード プロジェクトにのみ適用されます。 Android モード プロジェクトでは、除去を管理しているのは R8 です。 これはバイナリ サイズを減らすことと、攻撃対象領域を減らすことに役立ちます。 除去は、アプリケーションのエントリ ポイントを識別し、それらのポイントからアクセスできるすべてのコードを静的に分析することにより、自動的に動作します。 しかし、動的なリフレクションなどがあったりするため、静的な分析で、使用されているコードをすべて検出できるとは限りません。 このため、除去によってアプリケーションの機能が壊れる可能性があります。 除去が適用された後、機能テストのためのプロジェクト スケジュールを立てることは重要です。 また、どれくらい積極的に除去を適用するかを決定することも重要です。
名前の変更と同様に、エントリ ポイントが指定されていない場合、DashO はプロジェクトをライブラリのように扱い、パブリックのコード要素を除去しません。
DashO には、機能の問題のリスクは増大しますが、除去の積極性の度合いを増減できるオプションがあります。 設定が希望どおりになっているかを確認することは重要です。
Merge Inputs(機能)
Merge Inputs は、複数の入力を結合して 1 つの出力にする方法です。 これにより、配置シナリオを簡素化できるうえ、攻撃者がアプリケーションの構造を若干理解しづらくなるようにすることができます。 Merge Inputs は既定では無効になっているので、使用するには有効にする必要があります。
Android モードおよび標準モードの APK プロジェクトの場合、これらのプロジェクトでは常に 1 つの出力が生成されるため、Merge Inputs は実際にはオプションではありません。
ウォーターマーク
ウォーターマークは、攻撃者が簡単には見抜けないように、アプリケーションの構造にカスタム文字列を埋め込む方法です。 アプリケーションからウォーターマークを抽出して、特定のビルドを識別することができます。 これは、Android モードまたは標準モードの APK プロジェクトでは利用できません。
リリース準備
- チェックリストの手順に従っているか、あるいは、手順または機能を適用しない理由がわかり、記録されているかを確認する。
- 保護されたビルドが機能テストに合格しているかを確認する。
- 保護に関連するソース ファイルおよびビルド成果物が適切に保持されているかを確認する。
上記の手法を使用して、保護されたアプリケーションまたはライブラリが期待どおりに保護されているかを検証します。