Frida を使用したデータレポート

Frida を使用したデータレポート機能は永続化機能に基づいています。自身で作成した Frida スクリプトを介してメソッド呼び出しのデータを自動的にインターセプトし、我々が提供する特定のメソッドを通じてデータをレポートすることができます。データレポート機能を使用すると、スクリプトが取得したデータを Redis や外部の HTTP インターフェースに直接アップロードすることが容易になります。Redis や HTTP インターフェースを介してレポートされたデータコンテンツを受信できます。また、ネットワーク効率を最大化するため、データ圧縮後(zlib)のレポートもサポートしています。

注目

9.0 以降、内蔵されている frida 17.x では、frida-java-bridge をスクリプトに自身でパッケージ化する必要があります。そうしないと、`Java not defined` 関連のエラーが発生します。この変更は frida 公式の変更によるものであり、公式の変更説明に基づき、nodejs プロジェクトを新規作成し、java bridge を導入する必要があります。詳細は https://github.com/oleavr/frida-agent-example を参照するか、我々が提供する `tools/frida_script_generate.py` を使用して元の js スクリプトを再ラップしてください。

レポートスクリプトの作成

まず、Frida スクリプトを修正する必要があります。通常、Frida スクリプトには sendlog といった機能があり、外部にデータを送信できます。FIRERPA の場合、特定のメソッドを使用してデータを送信する必要があります。以下は、okhttp のトラフィックをインターセプトするためのテンプレートコードを使用したデモです。これはあくまでデモスクリプトであり、このスクリプトを正常に使用できない場合があります。以下のスクリプトは通常のスクリプトと大きな違いはありません。唯一の違いは emit メソッドを使用している点です。これは FIRERPA 独自のメソッドであり、これを使用することで、簡単かつ体系的に外部にデータを送信できます。

Java.perform(function() {
        Java.use("com.android.okhttp.internal.http.HttpEngine").getResponse.implementation = function() {
                var response = this.getResponse()
                var data = {}
                data["url"] = response._request.value._url.value._url.value
                data["body"] = response.body().string()
                emit("report_data", JSON.stringify(data))
                return response
        }
})

emit メソッドには emit(name, content) という2つの引数があります。name はデータのタイプを表します。レポート先のアドレスを redis に設定した場合、この名前は redis のキュー名を表します。できるだけ正確な英語で記述する必要があります(例:product_info)。content はデータの内容を表し、サポートされる型は文字列(string)とバイト配列(bytes)のみです。上記の例では、JSON 文字列に変換して送信しています。

これで、スクリプト作成に必要なフォーマットと呼び出し要件、つまりフックしたデータを外部に送信する方法について理解できました。次に、データレポートの送信先を設定する方法について、以下の内容を読み進めてください。

データレポートの送信先

データレポートの送信先は、スクリプト内で emit したデータをどこに送信するかを定義します。送信先として、HTTP インターフェース、Redis キュー、RabbitMQ キューがサポートされており、これらにはいくつかの違いがあります。

通常、データの送信元などの情報、つまりデータ送信元マシンを一致させる必要がない場合は、Redis キューの使用をお勧めします。逆に、一致させる必要がある場合は、HTTP または MQTT (v5) を使用すべきです。これらのプロトコルの特性上、プロトコルにより多くのメタデータを付与できるため、より正確なデバイスマッチングが可能になります。

レポートされるメタデータ

HTTP インターフェースおよび RabbitMQ を送信先とするデータには、元のレポートデータに加えて、プロトコル層からデバイスとスクリプトに関するメタデータを取得できます。プロトコルに含まれるメタデータは以下の表の通りです。

フィールド説明
applicationアプリケーションのパッケージ名(例:com.android.settings)
deviceデバイス ID(例:67b2a3d7-5004-ea2a-0d44-194de6ede8de)
encodeデータエンコーディング(例:none)
nameデータ名(例:report_data)
scriptスクリプト ID(例:7c52530d)
sequenceレポートシーケンス(例:30)
timestampレポートタイムスタンプ(例:1740023596914)
userマルチインスタンスアプリ ID(例:0)

注目

Redis プロトコルの特性上、Redis を送信先とするデータには上記のメタデータは一切含まれません。

device はデバイスの一意の ID です。リモートデスクトップの情報欄で確認できます。通常、この ID は一意で固定です。これを使用してデバイスをマークし、対応関係を確立できます。encode はデータエンコーディングで、nonezlib をサポートしています。zlib でエンコードされている場合、データ本体を zlib で解凍する必要があります。name はこのレポートデータのタイプをマークするために使用され、emit メソッドの最初の引数でもあります。sequence はレポートデータのインデックスを表し、0 から始まり、レポートごとにインクリメントされます。このフィールドを使用してデータをソートしたり、レポートの欠落がないかを確認したりできます。

レポート URL の追加パラメータ

レポート URL を組み立てる際に、URL 内に動的な ID パラメータを指定することがサポートされています。変数プレースホルダー ${name} の形式で、URL の特定の部分に挿入できます。http://192.168.1.2/report/${device_id} のような形式で使用します。サポートされている変数は以下の通りです。

名前説明
device_idデバイスの一意の ID
device_id_shortデバイスの一意の ID(BASE62 でエンコードされた短いデバイス ID)
android_idAndroid ID
serialnoro.serialno

HTTP へのレポート

レポートデータを受信するための HTTP サービスを自身で作成する必要があります。HTTP レポートインターフェースは POST メソッドを実装する必要があります。FIRERPA は POST を介してインターフェースにデータをレポートします。同時に、メタデータの各フィールドを HTTP クエリパラメータとしてエンコードします。そこから抽出して処理することができます。データ本体は、POST リクエストの body に含まれます。FIRERPA は 502、503、504 ステータスコードを受信した場合、自動的に 3 回リトライします。バックエンドがレポートデータを正しく受信して処理した場合、プレーンテキストの OK または SUCCESS を返し、ステータスコードを 200 に設定して処理の成功を示す必要があります。

注目

HTTP リクエストはマルチスレッドであるため、バックエンドが受信するメッセージはレポートシーケンス (`sequence`) に従わない可能性があります。
レポート URL の例 http://192.168.1.2/report/${device_id}?serialno=${serialno}
パスワード認証が必要な場合 http://user:password@192.168.1.2/report/${device_id}?serialno=${serialno}

MQTT へのレポート

MQTT へのレポートでは、レポートされるメタデータは UserProperty から抽出する必要があります。TLS、ユーザー名/パスワード認証、一方向証明書検証(サーバー証明書の検証)をサポートしており、双方向検証はサポートしていません。

レポート URL の例 mqtt://test.mosquitto.org:1883/script/${device_id}/report
パスワード認証が必要な場合 mqtt://rw:readwrite@test.mosquitto.org:1884/script/${device_id}/report

一方向検証が必要な場合 mqtts://test.mosquitto.org:8883/script/${device_id}/report?verify=true&ca=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVBekNDQXV1Z0F3SUJBZ0lVQlkxaGxDR3ZkajROaEJYa1ovdUxVWk5JTEF3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2daQXhDekFKQmdOVkJBWVRBa2RDTVJjd0ZRWURWUVFJREE1VmJtbDBaV1FnUzJsdVoyUnZiVEVPTUF3RwpBMVVFQnd3RlJHVnlZbmt4RWpBUUJnTlZCQW9NQ1UxdmMzRjFhWFIwYnpFTE1Ba0dBMVVFQ3d3Q1EwRXhGakFVCkJnTlZCQU1NRFcxdmMzRjFhWFIwYnk1dmNtY3hIekFkQmdrcWhraUc5dzBCQ1FFV0VISnZaMlZ5UUdGMFkyaHYKYnk1dmNtY3dIaGNOTWpBd05qQTVNVEV3TmpNNVdoY05NekF3TmpBM01URXdOak01V2pDQmtERUxNQWtHQTFVRQpCaE1DUjBJeEZ6QVZCZ05WQkFnTURsVnVhWFJsWkNCTGFXNW5aRzl0TVE0d0RBWURWUVFIREFWRVpYSmllVEVTCk1CQUdBMVVFQ2d3SlRXOXpjWFZwZEhSdk1Rc3dDUVlEVlFRTERBSkRRVEVXTUJRR0ExVUVBd3dOYlc5emNYVnAKZEhSdkxtOXlaekVmTUIwR0NTcUdTSWIzRFFFSkFSWVFjbTluWlhKQVlYUmphRzl2TG05eVp6Q0NBU0l3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFNRTBIS21JemZUT3drS0xUM1RISGUrT2JkaXphbVBnClVabUQ2NFRmM3pKZE5lWUdZbjRDRVhieVA2ZnkzdFdjOFMyYm9XNmR6ckg4U2RGZjl1bzMyMEdKQTlCN1UxRlcKVGUzeGRhL0xtM0pGZmFIamtXdzdqQndjYXVRWmpwR0lOSGFwSFJscGlDWnNxdUF0aE9neFc5U2dEZ1lsR3pFQQpzMDZwa0VGaU13K3FEZkxvL3N4RktCNnZRbEZla01lQ3ltakxDYk53UEp5cXloRm1QV3dpby9QRE1ydUJUelBICjNjaW9CbnJKV0tYYzNPalhkTEdGSk9majdwUDBqL2RyMkxINzJlU3Z2M1BRUUZsOTBDWlBGaHJDVWNSSFNTeG8KRTZ5akdPZG56N2Y2UHZlTElCNTc0a1FPUnd0OGVQbjB5aWRyVEMxaWN0aWtFRDNuSFloTVVPVUNBd0VBQWFOVApNRkV3SFFZRFZSME9CQllFRlBWVjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01COEdBMVVkSXdRWU1CYUFGUFZWCjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUwKQlFBRGdnRUJBR2E5a1MyMU43MFRoTTYvSGo5RDdtYlZ4S0xCalZXZTJUUHNHZmJsM3JFRGZaK09LUloyajZBQwo2cjdqYjRUWk8zZHpGMnA2ZGdicmxVNzFZLzRLMFRkeklqUmozY1EzS1NtNDFKdlVRMGhaL2MwNGlHRGcveFdmCitwcDU4bmZQQVl3dWVycnVQTldtbFN0V0FYZjBVVHFSdGc0aFFEV0J1VUZESlR1V3V1QnZFWHVkejc0ZWgvd0sKc013ZnUxSEZ2ank1WjBpTURVOFBVRGVwalZvbE9DdWU5YXNobFM0RUI1SUVDZFNSMlRJdG5BSWlJd2lteDgzOQpMZFVkUnVkYWZNdTVUNVhtYTE4Mk9DMC91L3hSbEVtK3R2S0dHbWZGY04wcGlxVmw4T3JTUEJnSWxiKzFJS0pFCm0vWHJpV3IvQ3E0aC9KZkI3TlRzZXpWc2xna0Jhb1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K

上記の URL では、関連データは script/${device_id}/report に送信されます。mosquitto_sub -L mqtt://test.mosquitto.org:1883/script/+/report のようなコマンドでこれらのメッセージをサブスクライブできます。

Redis へのレポート

Redis へのレポートは比較的シンプルです。メタデータが含まれていないため、データソースを直接区別することはできません。この動作を実現するには、インジェクトするスクリプトを動的に書き換える必要があるかもしれません。Redis へのレポートでは、FIRERPA はデータ本体を LPUSH を介して直接キューにプッシュします。例えば、前述のサンプルスクリプトでは、レポートデータは report_data キューにプッシュされます。

注目

スタンドアロンモードの Redis サービスのみをサポートしており、Redis クラスタはサポートしていません。

注目

パスワードフィールドを除き、redis の URL に変数プレースホルダーを追加しないでください。URL は標準の redis ライブラリがサポートする形式であり、他の部分を変更すると正しく解析できなくなる可能性があります。
レポート URL の例 redis://1.2.3.4/0
パスワード認証が必要な場合 redis://:password@1.2.3.4/0

TLS + パスワード

rediss://:password@1.2.3.4/0?ssl_ca_data=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURUVENDQWpXZ0F3SUJBZ0lVUFIvcmcxK0x2aU5tYzNsc0...

レポートスクリプトのインジェクト

もちろん、app インスタンスの取得が最初のステップです。上記の呼び出しで app 変数を取得できます。これは、インジェクト対象のアプリケーションのインスタンスを表します。その後、これを使用して後続のインジェクトまたはデタッチ操作を続行する必要があります。

app = d.application("com.android.settings")

以下のインターフェースを介して、上記で作成したレポートスクリプトをアプリケーションにインジェクトします。データがインターセプトされると、データは Redis の report_data キューに送信されます。この例では、デバイスが 192.168.1.10 上の関連サービスに直接アクセスできる必要があります。そうでない場合、データレポートは失敗します。

app.attach_script(script, emit="redis://192.168.1.10/0")

このように設定することもできます。この場合、データは Redis ではなく http インターフェースに送信されます(https をサポート)。

app.attach_script(script, emit="http://192.168.1.10/dataReport")

レポートするデータが大きい場合、圧縮を有効にするとネットワーク転送のスループットを大幅に向上させることができます。encode を使用してデータレポートの圧縮機能を有効にできます。もちろん、その後、受信側でレポートデータを解凍する必要があります。

app.attach_script(..., encode=DataEncode.DATA_ENCODE_ZLIB)

レポートデータの解凍

デフォルトでは、レポートデータは圧縮されません。レポートの圧縮を設定した場合、受信側で zlib を使用してレポートデータを解凍する必要があります。Python の公式ライブラリである zlib の decompress メソッドを使用すると、レポートデータを簡単に解凍できます。

zlib.decompress(data)

レポートスクリプトの削除

レポートスクリプトの削除プロセスは簡単で、永続化スクリプトでの使用方法と同じです。

app.detach_script()