Frida を使用したデータレポート¶
Frida を使用したデータレポート機能は永続化機能に基づいています。自身で作成した Frida スクリプトを介してメソッド呼び出しのデータを自動的にインターセプトし、我々が提供する特定のメソッドを通じてデータをレポートすることができます。データレポート機能を使用すると、スクリプトが取得したデータを Redis や外部の HTTP インターフェースに直接アップロードすることが容易になります。Redis や HTTP インターフェースを介してレポートされたデータコンテンツを受信できます。また、ネットワーク効率を最大化するため、データ圧縮後(zlib)のレポートもサポートしています。
注目
レポートスクリプトの作成¶
まず、Frida スクリプトを修正する必要があります。通常、Frida スクリプトには send や log といった機能があり、外部にデータを送信できます。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) |
注目
device はデバイスの一意の ID です。リモートデスクトップの情報欄で確認できます。通常、この ID は一意で固定です。これを使用してデバイスをマークし、対応関係を確立できます。encode はデータエンコーディングで、none と zlib をサポートしています。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_id | Android ID |
| serialno | ro.serialno |
HTTP へのレポート¶
レポートデータを受信するための HTTP サービスを自身で作成する必要があります。HTTP レポートインターフェースは POST メソッドを実装する必要があります。FIRERPA は POST を介してインターフェースにデータをレポートします。同時に、メタデータの各フィールドを HTTP クエリパラメータとしてエンコードします。そこから抽出して処理することができます。データ本体は、POST リクエストの body に含まれます。FIRERPA は 502、503、504 ステータスコードを受信した場合、自動的に 3 回リトライします。バックエンドがレポートデータを正しく受信して処理した場合、プレーンテキストの OK または SUCCESS を返し、ステータスコードを 200 に設定して処理の成功を示す必要があります。
注目
レポート 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 キューにプッシュされます。
注目
注目
レポート 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()