This post is also available in: English (英語)
概要
Android アプリケーション パッケージ (APK) サンプルを大規模に分析する際に直面する最大の課題の 1 つは、マルウェア作成者が使う Android プラットフォーム バージョンの多様性です。マルウェア検出空間で静的・動的解析技術を活用しようとすると、プラットフォーム バージョンの多様さに圧倒されることがあります。
本稿では、マルウェア作成者らが難読化を使って Android マルウェアを分析しづらいようにしている問題を取り上げます。また、難読化技術が実際どのように動作するのかを説明するため、ケース スタディを 2 つ検討します。最後に、汎用的な技術をいくつか紹介し、リサーチャーがこうした課題に対応できるようにします。
クラウド配信型マルウェア解析サービス Advanced WildFire (AWF) は本稿で取り上げたサンプルを「悪意のあるもの (malicious)」として正確に識別します。有効な AWF サブスクリプションをお持ちのパロアルトネットワークスのお客様は自動的にこれらの脅威からの保護を受けています。
関連する Unit 42 のトピック | Sandbox, Android |
フックベースのサンドボックス
マルウェア リサーチャーは静的・動的分析手法をどちらもよく使います。前者ではディスク上にあるマルウェア サンプルの特性を調べ、後者ではサンドボックス内でサンプルが実際どう動くのかを観察したりします。これら 2 つの手法を組み合わせれば、脅威がどのように振る舞うのか、その全体像を把握しやすくなります。
Android プラットフォームでは、動的分析で APK サンプルの実行を追跡し、マルウェア検出・分析用のランタイム情報を抽出します。動的分析で使えるサンドボックス手法の 1 つが、フック フレームワークの構築です。
フックとは、分析の実行中、サンプルが行う Android フレームワーク API の呼び出しをインターセプトする手法で、具体的には関数の引数と (あれば) 戻り値を捕捉・操作します。これは Android プラットフォーム特有のものではなく、同じ基本理論は、今日のあらゆる主要オペレーティング システムのネイティブ コードやマネージド コードで使えます。
以下の図 1 に示すように、フックは、実行時にユーザー指定の「フック」関数へのリダイレクトを挿入することによって実現されています。最新のサンドボックスは、フック技術に依存して、コード、データ (文字列)、埋め込みペイロードに対する、汎用的な実行時の難読化解除を提供しています。
フック フレームワークは、特定の Android プラットフォーム バージョンに固定されてはいません。サンプルのランタイムに対し、トレース ロジックを動的に追加することで、幅広い Android API レベルを柔軟にサポートしています。これによって、トレースの開発では、悪意のある振る舞いのトリガーと抽出に集中できるようになります。
このフレームワークの限界は、実行された Android フレームワーク API 関数内のすべてのコード行のインストルメンテーションはできないという点にあります。これは、インストルメンテーションが各命令のレベルではなく関数プロローグ (つまり関数の先頭) でバイトをパッチしてフック関数にジャンプして行われていることが理由です。しかし実際には、これでもリサーチャーにとってじゅうぶん納得できるトレードオフということはよくあります。
フック前 (オリジナル) |
フック後 (変更済み) |
図1. フックによるコード フローの変更
フック以外にも Android サンドボックスを実装する方法があります。Android オープン ソース プロジェクト (AOSP) のコードベースで関心のある特定のポイントにインストルメンテーションを追加することです。Android エコシステムはオープンソースなので、動的分析用に Android コードベースのカスタム ビルドを作成できます。
リサーチャーは、特定の戦略的ポイントにインストルメンテーション コードを挿入することで値を捕捉します。ショート メッセージ サービス (SMS) テキスト メッセージの読み取り関連の機微な Android フレームワーク API 関数などはインストルメンテーション候補の好例でしょう。これらの API 関数はマルウェア作成者によく悪用されているからです。これによってリサーチャーはサンプルの挙動に対する理解を深められます。
フックと比較したこのアプローチの利点は、Android フレームワーク API 全体を包括的にカバーしていることが保証されている点です。リサーチャーが関心対象の行に追加インスツルメンテーション コードを挿入して AOSP コードベースを再コンパイルすれば、すべてのコード行のインストルメンテーションが可能です (ただし再コンパイルはわりあい面倒です)。
この方法は分析対象サンプルに対して「透過的」でもあります。つまり、サンプル側からは自身がインストルメンテーションを挿入済みの AOSP 環境内で実行されているかどうかを区別できない可能性が高いということです。インストルメンテーションを使うと分析プロセスも速くなります。インストルメンテーションを使わなければ、難読化解除済みの悪性ペイロード (メモリ内にあるかドロップされたファイルとして存在する) をリサーチャー自身が発動前にアンパックせねばならなりません。
残念ながらこの方法だと、Android プラットフォームの進化にあわせて激しく修正される AOSP イメージをえんえんビルドしつづけるという高いコストがかかります。メジャー アップグレードや API の変更があるとこれがとくに問題となります。トレース モジュールを更新してこれらの新しいバージョンをサポートせねばならないからです。そうした例の 1 つが、Google が古い Dalvik ランタイムの使用から現在の Android ランタイム (ART) に移ったときにも起こっています。これは本質的に骨の折れるメンテナンス作業です。
API レベルのカバレッジ拡大
Google は Android プラットフォームを長年進化させつづけ、その過程でさまざまなバージョンを作成してきました。このため、これらのバージョンと関連付けられた、さまざまな API レベルが作成されています。図 2 は、2023 年 5 月時点の Android のさまざまなバージョンを示しています。
これらの各 API レベルでは、新たな機能を導入しつつ、デバイスの所有者にセキュリティ リスクをもたらす関数や古い関数を廃止していることがあります。APK サンプルの動的なインストルメンテーションを行っている場合はこれが問題となりえます。Android フレームワーク API 関数の仕様変更に伴って、開発者が既存のインストルメンテーション コードを定期的にメンテナンスする必要があるからです。
そこでフックの出番です。フックはデフォルトで拡張可能で、オンデマンドで複数の Android フレームワークの API レベルをサポートできます。
VirusTotal (VT) を検索したところ、2023 年 8 月 27 日から 9 月 7 日までの 12 日間に、12,394 件の悪意のある APK サンプルが見つかりました。これらの APK マルウェア サンプルの最小の API レベルのランタイム要件は、API レベル 19 から API レベル 30 までさまざまでした。図 3 はこれらの結果をまとめたグラフです。
注: Android API レベルの Webサイトによれば minSdkVersion とは「build.gradle で定義されるアプリがサポートする最小 SDK バージョン」とあります。 たとえば、あるアプリの minSDK が 26 であれば、この SDK バージョンは API レベル 26、つまり Android 8 に対応します。これはつまりそのアプリは Android 8 以降を搭載したデバイスでのみ実行される、ということを意味します。
同じ期間の弊社社内のテレメトリーからは同様の結果が観測されています (図 4)。
これらのサンプルでも最近の最小 API レベル ランタイム要件は広範囲にわたっていて、API レベル 19 から最新版の API レベル 34 までに及んでいました (図 5)。
最近では Google が 2023 年 8 月 31 日に「Google Play アプリの対象 API レベル要件」実施を発表しましたが、これ以降は年次で実施されることになります。こうした発表を受け、APK サンプルで利用可能な API レベル範囲は継続的に広がると予想されます。アップグレードには常に猶予期間が設けられていますし、サードパーティのアプリ ストア経由で配布するという代替手段もあるためです。
Google の現在の検出によれば、本稿で取り上げるマルウェア サンプルを含むアプリは Google Play ストア上には見つかりません。Google Play プロテクトは、Google Play 開発者サービス (Google Play Services) を稼働する Android デバイス上で、マルウェアが入っていると知られているアプリからユーザーを保護します。なお、そのアプリがサードパーティのストアから取得したものであっても同様に保護されます。
つまり、Google が新たに API レベルを公開するつど、時間がたつほどに新たなサポート対象の API レベルが広がっていくので、私たちはこれに WildFire サンドボックスを追随させていく必要があるということです。フックベースのサンドボックスの場合、オンデマンドでフックを追加・削除できるので、このメンテナンス作業はシンプルになります。
実行時の難読化解除
Android プラットフォームで APK サンプルが難読化される理由は、古典的な静的分析作業の妨害のためです。ほかのすべてのプラットフォームでも同様のことが起こっています。脅威アクターもベンダーも、多数のオプションのなかから、さまざまな難読化戦略を選んで簡単に切り替えることができます。オプションは多岐にわたり、すぐ入手できる商用ソリューションもあれば、無料のオープンソース ソフトウェアもあります。
こうした古典的静的解析手法での事情と異なり、それと似た問題が動的解析アプローチに不利に働くことはありません。動的分析は、難読化が完全に解除されてアンパックされたコア アーティファクトの捕捉と抽出に優れています。
APK/Dalvik のバイトコード (DEX) ペイロードと URL 文字列は、そうしたアーティファクトの一例です。APK は Android Application Package を指します。DEX は Android アプリケーションを動作させるコア プログラミング コードを意味します。URL 文字列は Web 経由で (たとえば https://paloaltonetworks.com などの) リモート エンドポイントに接続するためのサーバーのアドレスです 。
リサーチャーは識別や検出といった用途にくわえ、さらに分析を進めるためにもこうしたアーティファクトを必要とします。たしかに細かいところまで分析をすれば、アクティビティについての報告が必要なぶん、ランタイムも長びきます。それでも、インストルメンテーションを実施した環境で APK サンプルを発動させたとき、どのようなインタラクションが発生するのかを完全に観察する時間は必要なので、このプロセスを欠くことはできません。
「マルウェア作成者らは研究開発に多額の投資を行い、さまざまな回避技術を導入してから API サンプルを配布している」ということをリサーチャーは認識しておく必要があります。攻撃者は防御を突破できる技術のうち、最も手間のかからないものを選ぼうとします。それがだめならその時点でようやく技術更新を検討しはじめます。
動的分析アプローチの採用は、古典的静的分析よりも難読化の課題に取り組む上で有効です。サンドボックスは、こうした回避技術にも耐え、実行時に平文で利用できる有用なアーティファクトを明らかにしてくれます。
こうしたアーティファクトを使わない場合、APK サンプル内の DEX フローのトレースに多少苦労するでしょう。それなりにリソースを割いて、データベースの復号鍵などのトリッキーな値を手動で解決する必要もあります。私たちはリバース エンジニアリングを行い、APK サンプルに添付されているコード署名用のデジタル署名から暗号鍵が導出されていることを発見しました。
ケース スタディ
Cerberus バンキング トロージャン
Cerberus は、Android モバイル デバイスから価値の高い情報を窃取するバンキング トロージャン (バンキング型トロイの木馬) です。攻撃者はこのマルウェアでデバイスへのアクセスや制御を行い、所有者になりかわってアクションを実行できます。
Cerberus のサンプル (SHA-256 1249c4d3a4b499dc8a9a2b3591614966145daac808d440e5202335d9a4226ff8) は、ジェネリックな Android 証明書でデジタル コード署名されています。Google Play ストア アプリと同じアイコンを使って、同アプリを偽装します。ただしこの作成者は、連続する 5 つの空白文字 (\x20) を使ってアプリケーション名を空白にしています (図 6)。
さらにこの APK サンプルは、構成の文字列をすべて RC4 で暗号化したうえでさらに Base64 でエンコードして難読化しています。この APK サンプルは、単一のモノリシックな String Pool クラス内にこれらを変数値として格納しています。この APK サンプルは、表 1 に示した com.fky.lblabjglab というパッケージの a というクラスに a という名前の重要なメソッドを格納しています。
No | 変数名 | 構成キー (難読化) | 構成キー (難読化解除) |
1 | b | wssmnpdmydteY2Y3NGY4MzNmNg== | idbot |
2 | c | ujvsdjiocsqfMzg2Njg5ODcyZmExNzRkMzgxMjZkZjIyZTBhMw== | initialization |
3 | d | ysknmuiqllmjODRiMDRhNmJmZTQ4MDg1OTE2MDM4YTRiNGI= | urlAdminPanel |
4 | e | wdhinzpyayjvNDdlMzFkN2Q2MjU5MWZkMTVkZWZmMjE4Mjg5Mg== | starterService |
5 | f | vbylpyugkbfjYjZiMjgyNTY2ZmViZjA2YWM2ZTk1NTQyYTA= | statusInstall |
このサンプルは、図 7 に示したスキームに従って文字列を難読化します。
たとえば、idbot という入力文字列とランダムに選ばれた長さが 12 の小文字アルファベット暗号鍵 (wssmnpdmydte) が与えられると、この Android アプリケーション プロセスは、この鍵を使って入力文字列に RC4 暗号を適用します。得られたバイトは Base64 でエンコードされ、印刷可能な ASCII 文字 (Y2Y3NGY4MzNmNg==) となってロスレスで保存・送信されます。最後にこの Android アプリケーション プロセスは、選択された鍵をこの結果の先頭に追加して、最終的な難読化済みの文字列を生成します。これにより、逆の処理 (つまり、復号プロセス) が可能になります。
難読化された APK サンプルでは、ベーシックな Base64 エンコード (カスタム文字セットを使うこともある) がほどこされていたり、 1 バイトの固定鍵と文字列との XOR 演算を行って暗号化してあったりするケースをよく見かけます。それでなければ、ストリーム暗号 (RC4: Rivest Cipher 4) などのもっと強力で安全な暗号が使われるケースもよくあります。この Android アプリケーション プロセスもそうした例に当てはまりますが、若干ひねりが加わっています。このケースでは、鍵を前置し、DES (Data Encryption Standard) や AES (Advanced Encryption Standard) などの対称鍵暗号方式を使っています。
構成キーの難読化解除
文字列難読化ルーチンの識別に使える経験則は「高頻度で相互参照されているメソッドに目を向けろ」ということです。そうしたメソッドは多くの場合、少なくとも 1 つは文字列パラメーターの入力を受け取り、文字列のアウトプットを 1 つ戻り値として生成しているはずです。そうしたメソッドはたいていループ (たとえば 1 文字ずつ反復処理するもの) を含むスタンドアロンのメソッドで、Android フレームワークの API 関数にはほとんど依存していません。
実行を制御し、実行時のプログラムの状態と副作用を復元することで、サンドボックスは難読化を解除した状態の settings.xml という名前の構成ファイルを抽出できます。この Android アプリケーション プロセスは、この構成ファイルを Android アプリケーションのランタイム フォルダーの Shared Preferences に保存します。この Android アプリケーション プロセスは、初期化処理中に、ハードコードされた構成パラメーターを固定の値で難読化解除しながら、このファイルを繰り返し書き換えます。参考までにその抜粋を図 8 に示します。
このマルウェア ファミリーに属するサンプルからこれらの情報をパース・抽出する能力はすばやくスケール アップできます。これにより、次のことが容易になります。
- 実用的な脅威インテリジェンスを蓄積しアトリビューション (帰属) を行う
- 攻撃者の戦術・技術・手順 (TTP) への洞察を深める
- 時間経過とともに進化するこれらの脅威アクター グループを追跡する
HiddenAd アドウェア
HiddenAd は、Android ユーザーに広告を強引に表示してアドウェア作成者に収益をもたらすアドウェアです。その機能はほとんどの場合、無害な Android アプリケーションを装うことで隠されています。攻撃者がこのファミリーの一部の亜種を使い、べつのパッケージ化されたエクスプロイト キットやインフォスティーラーなどの悪意のあるツールを配布することもあります。
2 つめのケース スタディはこのマルウェア ファミリーのサンプル クラスターを中心に取り上げます。このサンプルは次のようなアクティビティを実行します。
- Android ランチャーのメニュー画面から自身のアプリケーション アイコンを隠す
- SQLCipher データベース暗号化を使って重要なセカンダリー ペイロードを保護する
「Bloons TD 6」の偽装
ここでは SHA-256 ハッシュ 73dee5433d560c072ea42b2288f826b16250da6f07543b3e3387ace31a13bd7c の Android APK サンプルを分析してその機能を実際に見ていきます。
攻撃者らは脅威アプリケーションのアイコンを非表示にしておけば戦術的に有利と考えています。これは、デバイスにどのようなアプリケーションをインストールしたかを確認するさい、Android ユーザーは Android ランチャーのメニュー画面 (図 9) を確認することが多いからです。
よく探せばこのサンプルの項目はアプリケーション リストに残っています。赤で強調表示した「Bloons TD 6」の行に注目してください。これがこのサンプルのアプリケーション名です。
このアプリケーション名は、マニフェスト ファイル AndroidManifest.xml 内にある <application> ノードの android:label 属性に由来します。このサンプルは、正規の Android ゲームを装おうとしています。Wikipedia のこのゲームについての説明 によれば、「Bloons TD 6」は Ninja Kiwi 氏が開発・公開した 2018 年のタワーディフェンス ゲームです。
このサンプルでは、次のステージで使う APK と DEX のペイロードを、暗号化した SQLite データベース ファイル内にカプセル化していました。またこのデータベース ファイルは、オリジナル サンプルの assets/ ディレクトリ内に埋め込まれていました。このマルウェアの作成者は、よく使われる SQLCipher の暗号化拡張機能をこの SQLite データベース ファイル内で有効にしていました。これによって Cipher Block Chaining (CBC) モードで動作する政府標準の AES 暗号 (256 ビット) が自動的に提供されることになります。
このサンプルの場合は SQLCipher 3(.5.9) のデフォルト設定でこの暗号化を使用しています。そのよい指標となるのが、オリジナル サンプルの lib/ ディレクトリーの下に、Android のネイティブ ライブラリーである libsqlcipher.so が存在していることです。
今回の場合、このサンプルにはデータベース ファイル muzikmp3mustafasandal.db が含まれていました。その暗号鍵は、サンプルに添付されたコード署名の電子署名の hashCode です。今回の場合、鍵は -923130181 という String でした。
このデータベース ファイルにはコア ペイロードである APK サンプルの muzikmp3mustafasandal.dat.jar と DEX バイトコードの ZnWjqpRHi.dex が含まれています。このコア ペイロードはデータベース内の iFqBWMAzy という名前のテーブルに以下の行として格納されています。
- テーブルの EQSnKGDYR という列にはファイル名を格納
- テーブルの bANpZqhWm という列には生のファイル コンテンツを格納
クラスター内のほかのサンプルには見られない、このサンプルのもつ特徴としてほかに URL 文字列を隠す方法があげられます。URL の各パーツを分離することで、正確な URL 文字列パターン マッチングを行う静的分析が失敗しやすいようにしています。URL のパーツを結合すれば完全な URL が復元されます。
このサンプルの場合元の URL は hxxp[://]madhavaapps[.]science/dwarkadhish/alternate148275android[.]php です (図 10)。
U+FFF8 の裏に隠れる
前の「Bloons TD 6」のサンプルとはちがい、似たようなもう 1 つの APK サンプル (SHA-256 ハッシュ833d9669dd64a2aa009a3741c8f16612cfafc3104b1f2113ac69255b6fcabf8e) は、正規の無害な Android アプリケーションの偽装はしていません。そのかわり、印刷できない「空」の Unicode (UTF-8) 文字である U+FFF8 (\xef\xbf\xb8) をラベルにもつ空白アイコンを使い、自身をアプリケーション リストの最後に追加します (図 11)。
こちらのサンプルは、前のサンプルが使っていた SQLCipher 3(.5.9) ではなく、SQLCipher 4(.3.0) のデフォルト設定を使っています。暗号鍵の導出方法は同じですが、こちらのサンプルには別の証明書が添付されているのでこの暗号鍵は -1463079363 という String に変わっています。
データベース ファイル名は com.db で、ここにコア ペイロードである APK サンプル com.dat.jar と DEX バイトコードの viVfyboRT.dex が含まれています。これらは、データベースの abaQwumOc という名前のテーブルに行として格納されています。このテーブルには 2 つ列があります。
- テーブルの DvaIESASI という列にはファイル名を格納
- テーブルの RsKesUrHq という列には生のファイル コンテンツを格納
net.sqlcipher.database パッケージ内の SQLiteOpenHelper クラスの getWritableDatabase メソッドにフックを配置すれば、この String パラメーター(つまり復号鍵)を捕捉して SQLCipher データベースの復号鍵を取得できます。
SQLCipher バージョン 3 と 4 のどちらが使われている場合でも、これで関連する暗号化パラメーターをまとめて判定できます。これらの暗号化パラメーターは次のとおりです。
- ページ サイズ
- 鍵導出関数 (KDF)
- KDF の反復回数
- HMAC (Hash Based Message Authentication Code: ハッシュ関数ベースのメッセージ認証コード) アルゴリズム
これらのパラメーターを集めるには、net.sqlcipher.database パッケージの SQLiteDatabase クラスのコンストラクターにフックを配置します。コンストラクターにフックを配置すると、SQLCIPHER_ANDROID_VERSION という静的 String フィールドの値を取得できます。
セカンダリー ステージ用の APK/DEX ペイロードの難読化を解除すれば、リサーチャーはこれらサンプル内部の動作をさらに深く知ることができます。防御側に真意を悟られにくいよう、攻撃者らはサンプルの作成を多層に分けて行うのがふつうです。これによって、とくに境界のセキュリティ防御を回避できる可能性が高まります。
こうした多層化戦略を採れば、たとえ多層化モジュール内の一部のコンポーネントがセキュリティ防御策に検出されても、そのコンポーネントだけ交換すればすみ、攻撃者にとっては汎用性が高まります。攻撃者はコンポーネントをあれこれ組みかえて、さまざまな組み合わせをつくりだせるので、防御側での検出ルールの指定や管理は煩雑になります。
結論
Android プラットフォームの急伸にともなって攻撃者はより広範囲の Android システムのバージョンを標的にしており、なかでも最近のバージョンが狙われています。お客様に一貫した保護を提供するため、Advanced WildFire (AWF) ではフック フレームワークとその関連技術を用いて、動的分析用のサンドボックスがサポートする Android API バージョンのカバレッジを広げてきました。
本稿では、静的分析アプローチでは発見が難しいような悪質な挙動も、フック フレームワークを使ったサンドボックスであれば識別できることを示しました。検出品質を高めるのに、こうした挙動の識別は欠かせません。
侵害の懸念があり弊社にインシデントレスポンスに関するご相談をなさりたい場合は、こちらのフォームからご連絡いただくか、infojapan@paloaltonetworks.comまでメールにてご連絡いただくか、下記の電話番号までお問い合わせください(ご相談は弊社製品のお客様には限定されません)。
- 北米フリーダイヤル: 1.866.486.4842 (+1.866.4.UNIT42)
- 英国: +44.20.3743.3660
- EMEA: +31.20.299.3130
- APAC: +65.6983.8730
- 日本: +81.50.1790.0200
パロアルトネットワークスは、ファイル サンプルや IoC (侵害指標) をふくむ調査結果を Cyber Threat Alliance (CTA: サイバー脅威アライアンス) のメンバーと共有しました。CTA のメンバーはこのインテリジェンスを使って、お客様に保護を迅速に提供し、悪意のあるサイバー攻撃者を体系的に阻害できます。詳細は Cyber Threat Alliance にてご確認ください。
IoC (侵害指標)
カテゴリー | 値 |
APKサンプル | Cerberus
HiddenAd
|
URL |
|
証明書のサムプリント (SHA-1) |
|
MITRE TTP (戦術・技術・手順)
ID | 技術 | 説明 |
T1628.001 | Hide Artifacts: Suppress Application Icon | APK サンプルは、アプリケーション ランチャーでユーザーにアイコンが表示されないようにします。
これにより、サンプルがインストールされているという事実が隠され、ユーザーがアプリケーションをアンインストールすることがより困難になる可能性があります。 |
T1406 | Obfuscated Files or Information | APK サンプルは、デバイス上または転送中のペイロードの内容を暗号化または難読化 (分割および連結) することにより、ペイロードの検出または分析を困難にします。
攻撃者は防御回避のためにさまざまなプラットフォームやネットワークをまたいでこうした振る舞いを見せる場合があります。検出を回避するためペイロードは暗号化ないし難読化されている場合があります。 |