Android Applications Basics

Support HackTricks

Android Security Model

二つのレイヤーがあります:

  • OSは、インストールされたアプリケーションを互いに隔離します。

  • アプリケーション自体は、開発者が特定の機能を公開し、アプリケーションの機能を設定することを可能にします。

UID Separation

各アプリケーションには特定のユーザーIDが割り当てられます。これはアプリのインストール時に行われ、アプリはそのユーザーIDが所有するファイルまたは共有ファイルとしか相互作用できません。したがって、アプリ自体、OSの特定のコンポーネント、およびルートユーザーのみがアプリのデータにアクセスできます。

UID Sharing

二つのアプリケーションは同じUIDを使用するように設定できます。これは情報を共有するのに便利ですが、一方が侵害されると両方のアプリケーションのデータが侵害されることになります。これがこの動作が推奨されない理由です同じUIDを共有するには、アプリケーションはマニフェスト内で同じandroid:sharedUserId値を定義する必要があります。

Sandboxing

Androidアプリケーションサンドボックスは、各アプリケーションを別のユーザーIDの下で別のプロセスとして実行することを可能にします。各プロセスは独自の仮想マシンを持っているため、アプリのコードは他のアプリから隔離されて実行されます。 Android 5.0(L)以降はSELinuxが強制されます。基本的に、SELinuxはすべてのプロセス間の相互作用を拒否し、その後、期待される相互作用のみを許可するポリシーを作成しました

Permissions

アプリをインストールするときに権限を要求されると、アプリはAndroidManifest.xmlファイル内の**uses-permission要素に設定された権限を要求しています。uses-permission要素は、name属性内で要求された権限の名前を示します。また、maxSdkVersion属性もあり、指定されたバージョンよりも高いバージョンでは権限の要求を停止します。 Androidアプリケーションは最初にすべての権限を要求する必要はなく、動的に権限を要求することもできますが、すべての権限はマニフェストに宣言されている必要があります**。

アプリが機能を公開する際には、特定の権限を持つアプリのみがアクセスできるように制限することができます。 権限要素には三つの属性があります:

  • 権限の名前

  • 関連する権限をグループ化するためのpermission-group属性。

  • 権限がどのように付与されるかを示すprotection-level。四つのタイプがあります:

  • Normal: アプリに既知の脅威がない場合に使用されます。ユーザーは承認する必要はありません

  • Dangerous: この権限が要求アプリケーションに昇格したアクセスを付与することを示します。ユーザーに承認を求められます

  • Signature: コンポーネントをエクスポートするものと同じ証明書で署名されたアプリのみが権限を付与されます。これは最も強力な保護タイプです。

  • SignatureOrSystem: コンポーネントをエクスポートするものと同じ証明書で署名されたアプリまたはシステムレベルのアクセスで実行されているアプリのみが権限を付与されます。

Pre-Installed Applications

これらのアプリは一般的に**/system/appまたは/system/priv-appディレクトリにあり、その中には最適化されたものもあります(classes.dexファイルが見つからないこともあります)。これらのアプリケーションは、時には過剰な権限で実行されている**ため、確認する価値があります(ルートとして)。

  • AOSP(Android OpenSource Project)ROMに付属しているもの

  • デバイスの製造元によって追加されたもの

  • 携帯電話のプロバイダーによって追加されたもの(彼らから購入した場合)

Rooting

物理的なAndroidデバイスにルートアクセスを取得するには、一般的に1つまたは2つの脆弱性を悪用する必要があります。これらは通常、デバイスおよびバージョンに特有です。 エクスプロイトが成功すると、通常、LinuxのsuバイナリがユーザーのPATH環境変数で指定された場所(例:/system/xbin)にコピーされます。

suバイナリが設定されると、別のAndroidアプリがsuバイナリとインターフェースし、ルートアクセスのリクエストを処理します。例えば、SuperuserSuperSU(Google Playストアで入手可能)などです。

ルート化プロセスは非常に危険であり、デバイスに深刻な損傷を与える可能性があることに注意してください。

ROMs

カスタムファームウェアをインストールすることでOSを置き換えることが可能です。これにより、古いデバイスの有用性を拡張したり、ソフトウェア制限を回避したり、最新のAndroidコードにアクセスしたりすることができます。 OmniROMLineageOSは使用するのに最も人気のあるファームウェアの二つです。

カスタムファームウェアをインストールするためにデバイスをルート化する必要はないことに注意してください一部の製造元は、文書化され、安全な方法でブートローダーのロック解除を許可しています。

Implications

デバイスがルート化されると、任意のアプリがルートとしてアクセスを要求できます。悪意のあるアプリケーションがそれを取得すると、ほぼすべてにアクセスでき、電話を損傷させることができます。

Android Application Fundamentals

  • Androidアプリケーションの形式は_ APKファイル形式_と呼ばれます。基本的にはZIPファイルです(ファイル拡張子を.zipに変更することで、内容を抽出して表示できます)。

  • APKの内容(網羅的ではありません)

  • AndroidManifest.xml

  • resources.arsc/strings.xml

  • resources.arsc: バイナリXMLのようなプリコンパイルされたリソースを含みます。

  • res/xml/files_paths.xml

  • META-INF/

  • ここに証明書が存在します!

  • classes.dex

  • Dalvikバイトコードを含み、アプリケーションがデフォルトで実行するコンパイルされたJava(またはKotlin)コードを表します。

  • lib/

  • CPUアーキテクチャごとにサブディレクトリに分けられたネイティブライブラリを格納します。

  • armeabi: ARMベースのプロセッサ用のコード

  • armeabi-v7a: ARMv7およびそれ以降のプロセッサ用のコード

  • x86: X86プロセッサ用のコード

  • mips: MIPSプロセッサ専用のコード

  • assets/

  • アプリに必要な雑多なファイルを格納し、追加のネイティブライブラリやDEXファイルを含む可能性があり、時にはマルウェア作成者が追加のコードを隠すために使用します。

  • res/

  • resources.arscにコンパイルされていないリソースを含みます。

Dalvik & Smali

Android開発では、JavaまたはKotlinがアプリ作成に使用されます。デスクトップアプリのようにJVMを使用する代わりに、AndroidはこのコードをDalvik実行可能(DEX)バイトコードにコンパイルします。以前は、Dalvik仮想マシンがこのバイトコードを処理していましたが、現在では新しいAndroidバージョンではAndroid Runtime(ART)が引き継いでいます。

リバースエンジニアリングでは、Smaliが重要になります。これはDEXバイトコードの人間が読めるバージョンで、ソースコードをバイトコード命令に変換するアセンブリ言語のように機能します。Smaliとbaksmaliは、この文脈でのアセンブリおよび逆アセンブリツールを指します。

Intents

インテントは、Androidアプリがそのコンポーネント間または他のアプリと通信するための主要な手段です。これらのメッセージオブジェクトは、アプリ間やコンポーネント間でデータを運ぶこともでき、HTTP通信でのGET/POSTリクエストのように機能します。

したがって、インテントは基本的にコンポーネント間で渡されるメッセージです。インテントは特定のコンポーネントやアプリに向けられることも、特定の受取人なしで送信されることもできます。 簡単に言えば、インテントは次のように使用できます:

  • アクティビティを開始するため、通常はアプリのユーザーインターフェースを開く

  • システムやアプリに変更を通知するためのブロードキャストとして

  • バックグラウンドサービスを開始、停止、通信するため

  • ContentProvidersを介してデータにアクセスするため

  • イベントを処理するためのコールバックとして

脆弱な場合、インテントはさまざまな攻撃を実行するために使用される可能性があります

Intent-Filter

インテントフィルターは、アクティビティ、サービス、またはブロードキャストレシーバーが異なるタイプのインテントとどのように相互作用できるかを定義します。基本的に、これらのコンポーネントの能力を説明し、どのようなアクションを実行できるか、またはどのようなブロードキャストを処理できるかを示します。これらのフィルターを宣言する主な場所はAndroidManifest.xmlファイル内ですが、ブロードキャストレシーバーの場合はコーディングすることも選択肢です。

インテントフィルターは、カテゴリ、アクション、およびデータフィルターで構成され、追加のメタデータを含めることができます。この設定により、コンポーネントは宣言された基準に一致する特定のインテントを処理できます。

Androidコンポーネント(アクティビティ/サービス/コンテンツプロバイダー/ブロードキャストレシーバー)の重要な側面は、その可視性または公開状態です。コンポーネントは、**exportedtrueの値である場合、またはマニフェスト内でインテントフィルターが宣言されている場合、公開と見なされ、他のアプリと相互作用できます。ただし、開発者はこれらのコンポーネントを明示的にプライベートに保つ方法があり、他のアプリと意図せず相互作用しないようにすることができます。これは、マニフェスト定義内でexported属性をfalse**に設定することで実現されます。

さらに、開発者は特定の権限を要求することで、これらのコンポーネントへのアクセスをさらに保護するオプションがあります。**permission**属性を設定することで、指定された権限を持つアプリのみがコンポーネントにアクセスできるようにし、誰がそれと相互作用できるかに対する追加のセキュリティと制御の層を追加します。

<activity android:name=".MyActivity" android:exported="false">
<!-- Intent filters go here -->
</activity>

インプリシットインテント

インテントは、インテントコンストラクタを使用してプログラム的に作成されます:

Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));

The Action of the previously declared intent is ACTION_SEND and the Extra is a mailto Uri (the Extra if the extra information the intent is expecting).

このインテントは、以下の例のようにマニフェスト内で宣言する必要があります:

<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

インテントフィルターは、メッセージを受信するためにアクションデータ、およびカテゴリが一致する必要があります。

「インテント解決」プロセスは、どのアプリが各メッセージを受信するかを決定します。このプロセスは、intent-filter宣言で設定できる優先度属性を考慮し、優先度が高い方が選択されます。この優先度は-1000から1000の間で設定でき、アプリケーションはSYSTEM_HIGH_PRIORITY値を使用できます。競合が発生した場合、「チョイザー」ウィンドウが表示され、ユーザーが決定できます

明示的インテント

明示的インテントは、ターゲットとするクラス名を指定します:

Intent downloadIntent = new (this, DownloadService.class):

他のアプリケーションでは、以前に宣言されたインテントにアクセスするために次のように使用できます:

Intent intent = new Intent();
intent.setClassName("com.other.app", "com.other.app.ServiceName");
context.startService(intent);

Pending Intents

これにより、他のアプリケーションがあなたのアプリケーションの代理でアクションを実行することができます。Pending Intentを構築する際には、インテントと実行するアクションを指定する必要があります。もし宣言されたインテントが明示的でない場合(どのインテントが呼び出せるかを宣言していない場合)、悪意のあるアプリケーションが被害者アプリの代理で宣言されたアクションを実行する可能性があります。さらに、アクションが指定されていない場合、悪意のあるアプリは被害者の代理で任意のアクションを実行できるようになります。

Broadcast Intents

前のインテントとは異なり、1つのアプリだけが受信するのではなく、ブロードキャストインテントは複数のアプリで受信可能です。ただし、APIバージョン14以降は、メッセージを受信するアプリを指定することが可能です。Intent.setPackageを使用します。

また、ブロードキャストを送信する際に権限を指定することも可能です。受信アプリはその権限を持っている必要があります。

ブロードキャストには2種類があります:通常(非同期)と順序付き(同期)。順序受信者要素内の設定された優先度に基づいています。各アプリはブロードキャストを処理、転送、または破棄することができます

Contextクラスの関数sendBroadcast(intent, receiverPermission)を使用してブロードキャストを送信することが可能です。 また、**LocalBroadCastManagersendBroadcast**関数を使用すると、メッセージがアプリを離れないことが保証されます。これを使用すると、受信者コンポーネントをエクスポートする必要すらありません。

Sticky Broadcasts

この種のブロードキャストは送信された後も長期間アクセス可能です。 これらはAPIレベル21で非推奨となり、使用しないことが推奨されていますこれにより、任意のアプリケーションがデータを盗聴することができるだけでなく、データを変更することも可能です

「sticky」という単語を含む関数(例:sendStickyBroadcastsendStickyBroadcastAsUser)を見つけた場合は、影響を確認し、削除を試みてください

Androidアプリケーションでは、ディープリンクを使用してURLを介して直接アクション(インテント)を開始します。これは、アクティビティ内で特定のURLスキームを宣言することによって行われます。Androidデバイスがこのスキームを持つURLにアクセスしようとすると、アプリケーション内の指定されたアクティビティが起動します。

スキームは**AndroidManifest.xml**ファイルに宣言する必要があります:

[...]
<activity android:name=".MyActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="examplescheme" />
</intent-filter>
[...]

前の例のスキームは exampleapp:// です(category BROWSABLE も注意してください)

次に、データフィールドで hostpath を指定できます:

<data android:scheme="examplescheme"
android:host="example"
/>

ウェブからアクセスするには、次のようにリンクを設定することができます:

<a href="examplescheme://example/something">click here</a>
<a href="examplescheme://example/javascript://%250dalert(1)">click here</a>

アプリで実行されるコードを見つけるために、ディープリンクによって呼び出されるアクティビティに移動し、**onNewIntent**関数を検索します。

HTMLページを使用せずにディープリンクを呼び出す方法を学ぶ

AIDL - Androidインターフェース定義言語

Androidインターフェース定義言語(AIDL)は、Androidアプリケーションにおけるプロセス間通信(IPC)を通じてクライアントとサービス間の通信を促進するために設計されています。別のプロセスのメモリに直接アクセスすることはAndroidでは許可されていないため、AIDLはオブジェクトをオペレーティングシステムが理解できる形式にマーシャリングすることで、異なるプロセス間の通信を容易にします。

主要概念

  • バウンドサービス: これらのサービスはIPCのためにAIDLを利用し、アクティビティやコンポーネントがサービスにバインドし、リクエストを行い、レスポンスを受け取ることを可能にします。サービスのクラス内のonBindメソッドは、相互作用を開始するために重要であり、脆弱性を探すためのセキュリティレビューにおいて重要な領域です。

  • メッセンジャー: バウンドサービスとして機能するメッセンジャーは、onBindメソッドを通じてデータを処理することに重点を置いたIPCを促進します。このメソッドを注意深く検査し、安全でないデータ処理や機密関数の実行がないか確認することが重要です。

  • バインダー: AIDLの抽象化によりバインダーの直接使用はあまり一般的ではありませんが、バインダーは異なるプロセスのメモリ空間間でデータ転送を促進するカーネルレベルのドライバーとして機能することを理解することは有益です。さらなる理解のために、リソースはhttps://www.youtube.com/watch?v=O-UHvFjxwZ8で利用可能です。

コンポーネント

これには、アクティビティ、サービス、ブロードキャストレシーバー、プロバイダーが含まれます。

ランチャーアクティビティと他のアクティビティ

Androidアプリでは、アクティビティは画面のようなもので、アプリのユーザーインターフェースの異なる部分を表示します。アプリは多くのアクティビティを持つことができ、それぞれがユーザーにユニークな画面を提供します。

ランチャーアクティビティはアプリへの主要な入り口であり、アプリのアイコンをタップすると起動します。これは、特定のMAINおよびLAUNCHERインテントを持つアプリのマニフェストファイルで定義されています。

<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

すべてのアプリがランチャーアクティビティを必要とするわけではなく、特にユーザーインターフェースのないバックグラウンドサービスのようなアプリは必要ありません。

アクティビティは、マニフェストで「exported」としてマークすることで、他のアプリやプロセスに利用可能にすることができます。この設定により、他のアプリがこのアクティビティを開始できるようになります:

<service android:name=".ExampleExportedService" android:exported="true"/>

しかし、別のアプリからアクティビティにアクセスすることが常にセキュリティリスクであるわけではありません。懸念は、機密データが不適切に共有される場合に生じ、情報漏洩につながる可能性があります。

アクティビティのライフサイクルはonCreateメソッドから始まり、UIを設定し、ユーザーとのインタラクションのためにアクティビティを準備します。

アプリケーションサブクラス

Android開発では、アプリはApplicationクラスのサブクラスを作成するオプションがありますが、必須ではありません。このようなサブクラスが定義されると、それはアプリ内で最初にインスタンス化されるクラスになります。**attachBaseContextメソッドがこのサブクラスで実装されている場合、onCreate**メソッドの前に実行されます。このセットアップにより、アプリケーションの残りの部分が開始される前に早期初期化が可能になります。

public class MyApp extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Initialization code here
}

@Override
public void onCreate() {
super.onCreate();
// More initialization code
}
}

サービス

Servicesバックグラウンドオペレーティブ であり、ユーザーインターフェースなしでタスクを実行することができます。これらのタスクは、ユーザーが異なるアプリケーションに切り替えても実行を続けることができるため、サービスは 長時間実行される操作 にとって重要です。

サービスは多用途であり、さまざまな方法で開始できますが、Intents がアプリケーションのエントリーポイントとしてサービスを起動する主な方法です。startService メソッドを使用してサービスが開始されると、その onStart メソッドが動作を開始し、stopService メソッドが明示的に呼び出されるまで実行を続けます。あるいは、サービスの役割がアクティブなクライアント接続に依存している場合、bindService メソッドを使用してクライアントをサービスにバインドし、データの受け渡しのために onBind メソッドを呼び出します。

サービスの興味深い応用には、バックグラウンドでの音楽再生やネットワークデータの取得が含まれ、ユーザーがアプリと対話することを妨げません。さらに、サービスは エクスポート を通じて同じデバイス上の他のプロセスにアクセス可能にすることができます。これはデフォルトの動作ではなく、Android Manifestファイルで明示的な設定が必要です:

<service android:name=".ExampleExportedService" android:exported="true"/>

Broadcast Receivers

Broadcast receivers は、メッセージングシステムにおけるリスナーとして機能し、複数のアプリケーションがシステムからの同じメッセージに応答できるようにします。アプリは Manifest を通じて、または registerReceiver API を介してアプリのコード内で 2つの主要な方法レシーバーを登録 できます。Manifest では、ブロードキャストは権限でフィルタリングされ、動的に登録されたレシーバーは登録時に権限を指定することもできます。

Intent フィルター は、両方の登録方法で重要であり、どのブロードキャストがレシーバーをトリガーするかを決定します。一致するブロードキャストが送信されると、レシーバーの onReceive メソッドが呼び出され、アプリが低バッテリーアラートに応じて動作を調整するなど、適切に反応できるようになります。

ブロードキャストは 非同期 であり、すべてのレシーバーに順序なしで到達することも、同期 であり、レシーバーが設定された優先順位に基づいてブロードキャストを受け取ることもできます。ただし、任意のアプリが自分自身を優先させてブロードキャストを傍受できる可能性があるため、潜在的なセキュリティリスクに注意することが重要です。

レシーバーの機能を理解するには、そのクラス内の onReceive メソッドを探してください。このメソッドのコードは受信した Intent を操作でき、特に Ordered Broadcasts では、データの検証がレシーバーによって必要であることを強調しています。Ordered Broadcasts は Intent を変更または削除することができます。

Content Provider

Content Providers は、アプリ間で 構造化データを共有する ために不可欠であり、データセキュリティを確保するために 権限 を実装する重要性を強調しています。これにより、アプリはデータベース、ファイルシステム、またはウェブなど、さまざまなソースからデータにアクセスできます。特定の権限、例えば readPermissionwritePermission は、アクセスを制御するために重要です。さらに、一時的なアクセスは、アプリのマニフェスト内の grantUriPermission 設定を通じて付与でき、pathpathPrefix、および pathPattern などの属性を利用して詳細なアクセス制御を行います。

入力検証は、SQL インジェクションなどの脆弱性を防ぐために重要です。Content Providers は、データ操作とアプリケーション間の共有を促進する基本的な操作をサポートしています:insert()update()delete()、および query()

FileProvider は、ファイルを安全に共有することに特化した Content Provider です。フォルダーへのアクセスを制御するために特定の属性を持ってアプリのマニフェストに定義され、android:exportedandroid:resource がフォルダー構成を指します。機密データが偶然に露出しないように、ディレクトリを共有する際には注意が必要です。

FileProvider の例のマニフェスト宣言:

<provider android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>

filepaths.xmlで共有フォルダーを指定する例:

<paths>
<files-path path="images/" name="myimages" />
</paths>

For further information check:

WebViews

WebViewsはAndroidアプリ内のミニウェブブラウザのようなもので、ウェブまたはローカルファイルからコンテンツを取得します。通常のブラウザと同様のリスクに直面しますが、特定の設定を通じてこれらのリスクを軽減する方法があります。

Androidは2つの主要なWebViewタイプを提供しています:

  • WebViewClientは基本的なHTMLには適していますが、JavaScriptのアラート機能をサポートしていないため、XSS攻撃のテストに影響を与えます。

  • WebChromeClientは、フルChromeブラウザの体験に近い動作をします。

重要な点は、WebViewブラウザはデバイスのメインブラウザとクッキーを共有しないことです。

コンテンツを読み込むために、loadUrl, loadData, および loadDataWithBaseURLなどのメソッドが利用可能です。これらのURLまたはファイルが安全に使用できることを確認することが重要です。セキュリティ設定はWebSettingsクラスを通じて管理できます。たとえば、setJavaScriptEnabled(false)でJavaScriptを無効にすることで、XSS攻撃を防ぐことができます。

JavaScriptの「ブリッジ」はJavaオブジェクトがJavaScriptと相互作用することを可能にし、Android 4.2以降はセキュリティのためにメソッドに@JavascriptInterfaceを付ける必要があります。

コンテンツアクセスを許可する(setAllowContentAccess(true))ことで、WebViewsはContent Providersにアクセスできますが、コンテンツURLが安全であることを確認しない限りリスクがあります。

ファイルアクセスを制御するために:

  • ファイルアクセスを無効にする(setAllowFileAccess(false))ことで、ファイルシステムへのアクセスが制限され、特定のアセットに対して例外が設けられ、機密性のないコンテンツのみに使用されることが保証されます。

Other App Components and Mobile Device Management

Digital Signing of Applications

  • デジタル署名はAndroidアプリに必須であり、インストール前に真正に作成されたことを保証します。このプロセスはアプリの識別のために証明書を使用し、インストール時にデバイスのパッケージマネージャーによって検証される必要があります。アプリは自己署名または外部CAによって認証され、無許可のアクセスから保護され、デバイスへの配信中にアプリが改ざんされないことを保証します。

App Verification for Enhanced Security

  • Android 4.2以降、Verify Appsという機能により、ユーザーはアプリをインストール前に安全性を確認できます。この検証プロセスは、潜在的に有害なアプリに対してユーザーに警告を発したり、特に悪意のあるアプリのインストールを防いだりすることができ、ユーザーのセキュリティを強化します。

Mobile Device Management (MDM)

  • MDMソリューションは、デバイス管理APIを通じてモバイルデバイスの監視とセキュリティを提供します。これらは、モバイルデバイスを効果的に管理および保護するためにAndroidアプリのインストールを必要とします。主な機能には、パスワードポリシーの強制ストレージ暗号化の義務付け、およびリモートデータ消去の許可が含まれ、モバイルデバイスに対する包括的な制御とセキュリティを確保します。

// Example of enforcing a password policy with MDM
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName adminComponent = new ComponentName(context, AdminReceiver.class);

if (dpm.isAdminActive(adminComponent)) {
// Set minimum password length
dpm.setPasswordMinimumLength(adminComponent, 8);
}
HackTricksをサポートする

Last updated