NHN Cloud Meetup 編集部
モバイルアプリのコードを保護するコード難読化機能
2020.07.30
4,749
概要
TOAST AppGuardでは、2020年5月にコード難読化機能を追加しました。今回はコード難読化の概念と機能について簡単に紹介したいと思います。コード難読化は、悪意を持ってアプリケーションのコードにアクセスする攻撃者からコードを保護する技術で、金融、決済、個人情報を使用するアプリには必ず適用すべき機能です。
現在は、関連するアプリのほとんどに、無料または有料のコード難読化機能を使用しています。ここで紹介するコード難読化機能と、難読化されていないコードの危険性を理解して、新規サービスのリリース時や既存サービスのセキュリティを強化する際に、お役立ていただけるとうれしいです。
コード難読化とは?
コード難読化とは、ソースコードを読み取りにくくし、可読性を下げる技術です。プログラマーが開発したソースコードの重要なアイデアやデータを、リバースエンジニアリング(reverse engineering)から保護するために主に使用されます。特に、元のソースコードが類推しやすいモバイルアプリでは必要な技術の1つであり、代表的な無料ツールとしてProGuardがあります。ソースコードが流出した場合、重要情報やコア技術が流出し、悪意のあるコードが挿入されるなどして、攻撃者の攻撃対象になることがあります。難読化は、これらの脅威からソースコードを保護するために必要な技術の1つです。
難読化のすすめ
OWASP、政府、金融セキュリティ研究者など、さまざまな機関から安全なモバイルサービスを提供するために難読化の適用が推奨されています。
OWASP Mobile 10
2016年に公開されたOWASP Mobile Risk Top 10では、ほとんどのアプリケーションは、コード固有の特性によりリバースエンジニアリングの影響を受ける、と紹介されています。大半の言語は、プログラマーがアプリをデバッグするのに役立つメタデータが豊富に存在し、このような機能は攻撃者がアプリの動作を理解する際に役立てられます。したがって、このような攻撃の脅威からアプリを防御するために難読化を推奨しています。
モバイル電子政府のサービス管理ガイドライン
NHN本社がある韓国では、2019年9月にモバイル電子政府のサービス管理ガイドラインを施行し、「行政機関等の長はガイドラインを遵守し、モバイルサービスの計画を策定して構築しなければならない」と明記しています。このガイドラインの10条、11条の項目では、モバイルセキュリティの脆弱性チェックと、ソースコードの検証についてガイドラインを提示しています。
民間モバイルサービスのセキュリティ脆弱性のチェックガイドは、韓国インターネット振興院が提供しています。そのガイドにおける第2章:機能セキュリティ脆弱性チェック方法、第5項:収集・活用および配布には、「アプリの改ざんを予防するため難読化ツールを使用し、モバイルアプリをパッケージ化して配布する」と書かれてあります。難読化されていないアプリが配布された場合は、アプリの構造とソースコードが改ざんされる脆弱性があるため、難読化の適用を推奨しています。
モバイル電子政府サービスアプリのソースコードの検証ガイドラインでも、モバイル環境に特化した脆弱性として、ソースコードの難読化が適用されていないことを挙げています。したがって、アプリの改ざんを防止するため、モバイルアプリの開発時にコード難読化ツールの適用を推奨しています。
電子金融サービスのセキュリティガイド
金融セキュリティ研究者が提供する電子金融サービスのセキュリティガイドでは、スマートフォンや電子金融サービスで提供される重要な機能が、悪意のある目的で変更されないように、重要モジュールを実装する際はアプリにリバースエンジニアリング防止技術を適用する必要があると指南しています。分析を困難にする機能は、ネイティブライブラリ(C/C++系列)などで実装し、セキュアコーディング、バイナリ(バイトコード、ネイティブコードなど)の難読化などの適用を提示しています。また「スマートフォンの電子金融サービスの安全対策チェックリスト」でも、実行可能なコード保護対策を適用しているかのチェック項目に、コード保護技術(難読化、暗号化など)が適用されているかチェックすることを推奨しています。
難読化されていないコードの危険性
ソースコードの流出
難読化されていないコードは、多くのセキュリティ上の脅威にさらされる恐れがあります。代表的なセキュリティの脅威として、逆コンパイルにより誰でもソースコードの原本を簡単に確認できるというリスクがあります。
Androidアプリの無料逆コンパイルツールとしてよく使われているjadxは、簡単に使用することができ、ソースコードの逆コンパイル、AndroidManifest、resourceなどをデコードして、アナリストが見やすい形に表示します。
JEBのような商用ツールでも逆コンパイルのみならず、さまざまな機能をサポートし、簡単にアプリを分析できるようにサポートします。
iOSの場合は、ルーティングされた端末から復号化されたアプリのバイナリを抽出して、IDA Proの逆コンパイルプラグインHex-Rayを使用すると、ソースコードの情報を取得できます。元のソースコードと同一ではありませんが、下図のように類似したソースコードを取得することができます。
改ざんの容易性
ソースコードの流出は、企業のコア技術の流出リスクや、攻撃者に簡単に攻撃ポイントを公開してしまうセキュリティの脅威にさらされる恐れがあります。Androidの場合は、さまざまな方法でapkファイルを確保し、オープンソースツールであるApktoolを利用してsmaliを抽出し、アプリを改ざんすることができます。(下図参照)smaliファイルは、Dalvikバイトコードで構成されており、簡単にコードを挿入したり削除することができます。Apktoolの使用方法やsmaliコードの改ざん方法は、インターネット上で公開されており、誰でも容易に改ざんすることができます。
攻撃者は、逆コンパイルされたソースコードから改ざんのポイントを探し、smaliを変更してセキュリティロジックの迂回や、悪意のある行為などを行います。改ざん後にApktoolにリパッケージして配布するケースも多数発生しています。代表的な例として、BlackMod、Android Republicのようなゲーム改ざんアプリの配布サイトがあります。
無料難読化ツール(ProGuard)の限界
Android Studioでは、無料でProGuardという難読化ツールを提供しています。ProGuardは、クラス、メソッド、フィールド名と同じ識別子情報をランダムな文字に変更し、開発者が命名した識別子の役割を隠す機能を提供します。
識別子がランダムな文字に変更されると、クラス、メソッドの役割が一部隠されますが、内部コードを分析して簡単に開発者の意図を把握できるという問題が存在します。たとえば、下図のように識別子情報を隠しても、文字列を表示して呼び出すAPI分析によって、当該メソッドがどのような役割をするか把握することができます。
ProGuardのような無料ツールは、識別子情報を難読化して開発者の意図を簡単には見つけられないようにする機能を提供していますが、攻撃者が少し時間をかければ簡単にクラスやメソッドの役割を把握できるため、限界があります。したがって、識別子以外にもさまざまな難読化技術を適用してソースコードを保護する必要があります。
コード難読化機能の概要
ユーザーコードを保護するコード難読化機能にはさまざまな方法がありますが、代表的なものとして、次のような機能を提供します。
識別子の難読化
識別子難読化機能は、開発者が定義したクラス、メソッド、フィールド名を識別しにくい値に変更することにより、各クラス、メソッド、変数がどのような目的で定義されたか、情報を隠す役割をします。難読化前(左図)は各変数がどのような役割をするか識別できますが、難読化後(右図)は、識別しにくいランダムな文字列で構成されていることがわかります。
文字列の暗号化
文字列暗号化機能は、コード内で使用する文字列を暗号化する機能で、文字列で構成された重要情報を隠す役割をします。文字列は攻撃ポイントを探すのに利用されることもあり、アプリ内の重要情報も含むため、情報流出のセキュリティの脅威があります。これらの文字列を下図のように攻撃者が容易に識別できない文字で暗号化して分析を妨害します。
制御フローの難読化
制御フロー難読化は、コードフローの分析を困難にする技術で、次のようにswitch-case文を使用したり、ifなどの条件文を使用してコードフローを隠す役割をします。下図のようにコードフローが難読化されると、コードの実行順序、フローの把握が困難になり、対象の関数の正確な動作構造が把握しにくくなります。
メソッド呼び出しの非表示化
メソッド呼び出し非表示機能は、コード内で呼び出すメソッドとAPI情報を隠して、メソッドの呼び出しフローと動作情報を隠す役割をします。呼び出されるAPI情報が隠されると、当該メソッドがどのような役割をするか識別するのが非常に困難になるというメリットがあります。難読化前(左図)は、startActiviy、killProcess関数などが呼び出されるAPI情報を確認できますが、難読化後(右図)は、APIの呼び出しポイントが確認できないことがわかります。
ダミーコードの挿入
ダミーコードの挿入は、コード実行に影響しないダミーコード(ゴミコード)を挿入して分析に混乱を与える技法です。分析が必要なコード量が増えることで、分析を遅延させる役割をします。右図のように実行されないコードを挿入して分析に混乱を与えることができます。
逆コンパイル/リパッケージ防止
逆コンパイル/リパッケージ防止は難読化機能というよりも、特定ツールのバグを利用して逆コンパイル/リパッケージがされないようにする技術です。逆コンパイル防止機能は、無料の逆コンパイルツールであるJADXなどのツールを使って、逆コンパイルされたソースコードを確認できないようにするもので、適用すると右図のように逆コンパイル時にエラーを出力します。
リパッケージ防止機能は、Apktoolのようなapkリパッケージツールのバグを利用して、適用すると右図のように、アンパッケージング時にエラーを発生させる機能です。アンパッケージが正常にできないとリパッケージできないため、攻撃者がアプリを改ざんしてリパッケージするのを難しくします。
デバッグ情報の削除
デバッグ情報の削除は、開発者がデバッグのために残したデータを削除する機能です。デバッグ情報は開発者が楽にデバッグできるように用いられます。攻撃者はこれを利用して攻撃ポイントを探すことがあるため、デバッグ情報を削除して攻撃者が識別できるメタ情報を取り除き、分析ポイントを減らすことができます。
まとめ
たくさんの労力と時間をかけて準備したサービスが攻撃者によって簡単にハッキングされたり、コア技術が露出してしまうといった被害が頻繁に発生しています。難読化を利用してコードを保護することで、ハッキングのリスクを落とし、自社のコア技術を保護する効果が得られます。しかし、コード難読化はアプリサービスを保護するための完璧な技術ではありません。サービスを保護するにはコード難読化も必要ですが、OSの改ざん検出(ルーティング/脱獄など)、アプリの改ざん検出、ネットワーク中間者攻撃(SSL pinning攻撃)の検出、フィッシング対策など、さまざまな保護技術を取り入れることで、安全なアプリサービスを提供することができます。
TOAST AppGuardでは、安全なモバイルサービスをサポートするため、コード難読化機能を新たにリリースしました。コード難読化機能では、上記で紹介した難読化機能に加え、OSの改ざん検出、アプリの改ざん検出、ネットワーク中間者攻撃の保護、遠隔制御アプリによるフィッシング対策などのさまざまな保護技術を提供し、より安全なモバイルサービスが提供できるようにサポートしています。