Frida Data Reporting

The data reporting functionality using Frida is based on the persistence feature. You can use your Frida scripts to automatically intercept method call data and report it via our specific method. The data reporting feature allows you to easily send the data intercepted by your script directly to Redis, MQTT, or an external HTTP interface, and you can receive the reported data content through Redis, MQTT, or an HTTP interface. To maximize network efficiency, data compression (zlib) is also supported before reporting.

Attention

Since version 9.0, the built-in Frida 17.x requires you to bundle frida-java-bridge into your script yourself; otherwise, errors related to Java not defined will occur. This change is from Frida official. According to the official change instructions, you need to create a Node.js project and introduce frida-java-bridge. For details, refer to: https://github.com/oleavr/frida-agent-example , or use the frida_script_generate.py we provide to bundle the JS script.

Writing a Reporting Script

Usually, Frida scripts have functions like send and log to send data to the outside, but for FIRERPA, you need to use a specific method to send data out. The following uses our template code for OkHttp traffic interception as a demonstration. It is just a demo script and may not work properly for you. The script below is not much different from regular scripts, the only difference being the use of an emit method, which is a built-in method of FIRERPA. You can use it to conveniently and systematically submit data to the outside.

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
        }
})

The submission method has two parameters: emit(name, content). name represents the type of data; if your reporting destination is set to Redis, this name represents the Redis queue name. You should describe it as accurately as possible in English, e.g., product_info. content represents the data content, and the type supports only strings and byte arrays. In the example, we converted it to a string for submission.

Now you understand the format and calling requirements for script writing, i.e., how to submit Hooked data to the outside. You also need to continue reading below to learn how to configure the data reporting destination.

Data Reporting Destination

The data reporting destination indicates where the data emitted in your script should be sent. Supported destination types include HTTP interfaces, Redis queues, and MQTT. There are some differences among them.

In general, if you don't need to care about information such as data sources, i.e., you don't need to match data with source device, we recommend using Redis queues. Otherwise, you should use HTTP or MQTT (v5), because these protocols can carry more metadata, allowing you to perform more precise device matching.

Reporting Metadata

For data reported to HTTP interfaces and MQTT destinations, in addition to the original report data, you can also obtain metadata about the device and script at the protocol layer. The metadata carried in the protocol is shown in the table below.

FieldDescription
applicationApp package name (e.g., com.android.settings)
deviceDevice ID (e.g., 67b2a3d7-5004-ea2a-0d44-194de6ede8de)
encodeData encoding (none
nameData name (e.g., report_data)
scriptScript ID (e.g., 7c52530d)
sequenceReporting sequence (e.g., 30)
timestampReporting time (e.g., 1740023596914)
userMulti-app user ID (e.g., 0)

Attention

Due to the nature of the Redis protocol, data reported to a Redis destination does not include any of the above metadata.

device is the unique device ID; you can find it in the remote desktop information bar. Usually, this ID is unique and fixed. You can use it to mark the device and establish a correspondence. encode is the data encoding; supported encodings are none and zlib. If the encoding is zlib, you need to decompress the data body using zlib. name marks the type of this reported data; it is also the first parameter when you call the emit method. sequence represents the index of the reported data, starting from 0 and incrementing with each report. You can use this field to sort the data or check for report loss.

You can specify some dynamic id parameters in the reporting link using the variable placeholder format ${name} inserted into specific parts of the link. For example, http://192.168.1.2/report/${device_id}. The supported variables are shown in the table below.

NameDescription
device_idUnique device ID
device_id_shortUnique device ID (short device ID encoded in BASE62)
android_idAndroid ID
serialnoro.serialno

Reporting to HTTP

You need to write an HTTP service to receive the reported data yourself. The HTTP reporting interface must implement the POST method. FIRERPA will report data to the interface via POST, and will encode each field of the metadata as HTTP query parameters, which you can extract and process. The data body is carried in the POST request body. FIRERPA will automatically retry up to 3 times upon receiving 502, 503, or 504 status codes. If your backend correctly receives and processes the reported data, it should return plain text OK or SUCCESS with a 200 status code to indicate successful processing.

Attention

HTTP requests are multi-threaded; the messages received by the backend may not follow the reporting sequence (sequence).

http://192.168.1.2/report/${device_id}?serialno=${serialno}

If standard HTTP protocol authentication is required:

http://user:password@192.168.1.2/report/${device_id}?serialno=${serialno}

Reporting to MQTT

When reporting to MQTT, the metadata can be extracted from UserProperty. It supports TLS, username/password, and one-way certificate verification (server certificate verification).

mqtt://test.mosquitto.org:1883/script/${device_id}/report

MQTT with password authentication:

mqtt://rw:readwrite@test.mosquitto.org:1884/script/${device_id}/report

Requiring server certificate authentication:

mqtts://test.mosquitto.org:8883/script/${device_id}/report?verify=true&ca=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVBekNDQXV1Z0F3SUJBZ0lVQlkxaGxDR3ZkajROaEJYa1ovdUxVWk5JTEF3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2daQXhDekFKQmdOVkJBWVRBa2RDTVJjd0ZRWURWUVFJREE1VmJtbDBaV1FnUzJsdVoyUnZiVEVPTUF3RwpBMVVFQnd3RlJHVnlZbmt4RWpBUUJnTlZCQW9NQ1UxdmMzRjFhWFIwYnpFTE1Ba0dBMVVFQ3d3Q1EwRXhGakFVCkJnTlZCQU1NRFcxdmMzRjFhWFIwYnk1dmNtY3hIekFkQmdrcWhraUc5dzBCQ1FFV0VISnZaMlZ5UUdGMFkyaHYKYnk1dmNtY3dIaGNOTWpBd05qQTVNVEV3TmpNNVdoY05NekF3TmpBM01URXdOak01V2pDQmtERUxNQWtHQTFVRQpCaE1DUjBJeEZ6QVZCZ05WQkFnTURsVnVhWFJsWkNCTGFXNW5aRzl0TVE0d0RBWURWUVFIREFWRVpYSmllVEVTCk1CQUdBMVVFQ2d3SlRXOXpjWFZwZEhSdk1Rc3dDUVlEVlFRTERBSkRRVEVXTUJRR0ExVUVBd3dOYlc5emNYVnAKZEhSdkxtOXlaekVmTUIwR0NTcUdTSWIzRFFFSkFSWVFjbTluWlhKQVlYUmphRzl2TG05eVp6Q0NBU0l3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFNRTBIS21JemZUT3drS0xUM1RISGUrT2JkaXphbVBnClVabUQ2NFRmM3pKZE5lWUdZbjRDRVhieVA2ZnkzdFdjOFMyYm9XNmR6ckg4U2RGZjl1bzMyMEdKQTlCN1UxRlcKVGUzeGRhL0xtM0pGZmFIamtXdzdqQndjYXVRWmpwR0lOSGFwSFJscGlDWnNxdUF0aE9neFc5U2dEZ1lsR3pFQQpzMDZwa0VGaU13K3FEZkxvL3N4RktCNnZRbEZla01lQ3ltakxDYk53UEp5cXloRm1QV3dpby9QRE1ydUJUelBICjNjaW9CbnJKV0tYYzNPalhkTEdGSk9majdwUDBqL2RyMkxINzJlU3Z2M1BRUUZsOTBDWlBGaHJDVWNSSFNTeG8KRTZ5akdPZG56N2Y2UHZlTElCNTc0a1FPUnd0OGVQbjB5aWRyVEMxaWN0aWtFRDNuSFloTVVPVUNBd0VBQWFOVApNRkV3SFFZRFZSME9CQllFRlBWVjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01COEdBMVVkSXdRWU1CYUFGUFZWCjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUwKQlFBRGdnRUJBR2E5a1MyMU43MFRoTTYvSGo5RDdtYlZ4S0xCalZXZTJUUHNHZmJsM3JFRGZaK09LUloyajZBQwo2cjdqYjRUWk8zZHpGMnA2ZGdicmxVNzFZLzRLMFRkeklqUmozY1EzS1NtNDFKdlVRMGhaL2MwNGlHRGcveFdmCitwcDU4bmZQQVl3dWVycnVQTldtbFN0V0FYZjBVVHFSdGc0aFFEV0J1VUZESlR1V3V1QnZFWHVkejc0ZWgvd0sKc013ZnUxSEZ2ank1WjBpTURVOFBVRGVwalZvbE9DdWU5YXNobFM0RUI1SUVDZFNSMlRJdG5BSWlJd2lteDgzOQpMZFVkUnVkYWZNdTVUNVhtYTE4Mk9DMC91L3hSbEVtK3R2S0dHbWZGY04wcGlxVmw4T3JTUEJnSWxiKzFJS0pFCm0vWHJpV3IvQ3E0aC9KZkI3TlRzZXpWc2xna0Jhb1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K

In the above link, the relevant data will be sent to the topic script/${device_id}/report. You can subscribe to these messages using something like mosquitto_sub -L mqtt://test.mosquitto.org:1883/script/+/report.

Reporting to Redis

Redis reporting is relatively simple. Because it does not carry any metadata, you cannot directly distinguish the data source. You may need to achieve this by dynamically modifying the injected script. For Redis reporting, FIRERPA will directly push the data body into the queue via LPUSH. For example, in the example script above, the reported data will be pushed into the report_data queue.

Attention

Only standalone Redis service is supported; Redis cluster is not supported. Except for the password field, do not add variable placeholders in the Redis link. The link is in the format supported by the standard Redis library; modifying other parts may cause parsing errors.

redis://1.2.3.4/0

Redis requiring password authentication:

redis://:password@1.2.3.4/0

TLS + password authentication Redis:

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

Injecting the Reporting Script

Of course, obtaining the app instance is the first step. You can obtain an app variable through the above calls, which represents the application instance you need to inject. You then need to use it to perform subsequent injection or detachment operations.

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

Inject the above reporting script into the application. When data is intercepted, it will be submitted to the Redis report_data queue. In the example, your device needs direct access to the relevant service on 192.168.1.10; otherwise, it will not receive the data.

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

Calling it this way will submit your data to an HTTP interface instead of Redis (HTTPS supported).

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

When the data you report is large, enabling compression can significantly improve network transmission throughput. You can use the encode parameter to enable report data compression and need to decompress the data on the receiving end.

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

Decompressing Reported Data

By default, reported data is not compressed. If you have enabled reporting compression, you also need to decompress the reported data on the receiving end using zlib. You can conveniently decompress the reported data using the standard Python library zlib's decompress method.

zlib.decompress(data)

Removing the Reporting Script

Removing the reporting script is straightforward, just like the usage in the persistence script.

app.detach_script()