Using Frida to Report Data¶
The function of using Frida to report data is based on persistence functionality. You can automatically capture method call data through your written Frida scripts and report the data through our specific methods. The data reporting function allows you to easily upload data captured by scripts directly to Redis or external HTTP interfaces. You can receive the reported data content through Redis or HTTP interfaces. At the same time, to maximize network performance, data compression (zlib) is supported before reporting.
Writing Reporting Scripts¶
The first step is to modify your Frida script. Typically, Frida scripts have features like send
and log
that allow you to send data externally. For FIRERPA, you need to use specific methods to send out data. The following uses our template code for intercepting okhttp traffic as a demonstration. It is just a demonstration script, and you may not be able to use this script normally. The following script is not much different from regular scripts; the only difference is the use of an emit
method, which is a built-in method in FIRERPA that allows you to conveniently and systematically submit data externally.
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 emit method has two parameters: emit(name, content)
. Here, name
represents the type of data. If your reporting address is set to Redis, then this name represents the Redis queue name. You should try to accurately describe it in English, such as product_info
. content
represents the content of the data, and the type only supports string and byte array (bytes). In the above example, we converted it to a JSON string for submission.
Now, you understand the format and calling requirements needed for script writing, which is how to submit the hooked data externally. You also need to continue reading the following to understand how to configure the destination of data reporting.
Data Reporting Destination¶
The data reporting destination represents where the data you emit in the script should be sent. The supported destination types include HTTP interfaces, Redis queues, and RabbitMQ queues, which have some slight differences.
Typically, if you don’t need to worry about data sources and other information, i.e., you don’t need to match data with source machines, we recommend using Redis queues. Otherwise, you should use HTTP or RabbitMQ queues, because due to the protocol characteristics of these two, we can carry more metadata in the protocol, allowing for more precise device matching.
Reported Metadata¶
For data reported to HTTP interfaces and RabbitMQ destinations, in addition to containing the original reported data, you can also obtain metadata about the device and script through the protocol layer. The metadata included in the protocol is shown in the table below.
Field | Description |
---|---|
application | Application package name (e.g., com.android.settings) |
device | Device ID (e.g., 67b2a3d7-5004-ea2a-0d44-194de6ede8de) |
encode | Data encoding (e.g., none) |
name | Data name (e.g., report_data) |
script | Script ID (e.g., 7c52530d) |
sequence | Reporting sequence (e.g., 30) |
timestamp | Reporting time (e.g., 1740023596914) |
user | Multi-instance application ID (e.g., 0) |
Attention
Due to Redis protocol characteristics, data reported to Redis destinations does not include any of the above metadata.
device
is the unique ID of the device, which you can find in the information bar of the remote desktop. Usually, this ID is unique and fixed. You can use it to mark the device to create corresponding relationships. encode
is the data encoding, which supports none
and zlib
. If the encoding is zlib, you need to use zlib to decompress the data. name
is used to mark the type of reported data, and it is also the first parameter when you use 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 missing reports.
Reporting to HTTP¶
You need to write your own HTTP service to receive the reported data. The HTTP reporting interface needs to implement the POST method. FIRERPA will report data to the interface via POST and will encode each field in the metadata as HTTP query parameters, which you can extract and process. For the data body, it is carried in the body of the POST request. FIRERPA will automatically retry 3 times when receiving status codes 502, 503, and 504. If your backend correctly receives and processes the reported data, it should return plain text OK
or SUCCESS
and set the status code to 200
to indicate successful processing.
Attention
HTTP requests are multi-threaded, and messages received by the backend may not follow the reporting order (sequence).
Reporting to RabbitMQ¶
For reporting to RabbitMQ queues, FIRERPA will not automatically create queues for you; you need to create them yourself. In the example script above, you need to create the report_data
queue in advance. For the reported metadata, you should extract it from the Header
.
Reporting to Redis¶
Redis reporting is relatively simple. Since it does not carry any metadata, it cannot directly distinguish data sources. You may need to implement this behavior by dynamically rewriting the injection script. For Redis reporting, FIRERPA will directly push the data body into the queue using the LPUSH
method. For example, in the example script above, the reported data will be pushed into the report_data
queue.
Attention
Only standalone Redis services are supported, Redis clusters are not supported.
Injecting Reporting Scripts¶
Of course, getting the app instance is the first step. You can obtain an app
variable through the above call, which represents the instance of the application you need to inject. Then you need to continue with the following injection or detachment operations through it.
app = d.application("com.android.settings")
Inject the above reporting script into the application using the following interface. When data is intercepted, it will be submitted to the report_data queue in Redis. In the example, your device needs to be able to directly access the relevant services on 192.168.1.10, otherwise, it will not be able to report data.
app.attach_script(script, emit="redis://192.168.1.10/0")
You can also set it up like this, so your data will be submitted to the HTTP interface instead of Redis (HTTPS is supported).
app.attach_script(script, emit="http://192.168.1.10/dataReport")
When your reported data is large, enabling compression can greatly improve network transmission throughput performance. You can use encode
to enable data compression for reporting. Of course, you will also need to decompress the reported data afterward.
app.attach_script(..., encode=DataEncode.DATA_ENCODE_ZLIB)
Decompressing Reported Data¶
By default, reported data has no compression. If you have set up report compression, you will also need to use zlib encoding at the receiving end to decompress the reported data. You can use the decompress
method of the Python official library zlib to conveniently decompress the reported data.
zlib.decompress(data)
Removing Reporting Scripts¶
The process of removing reporting scripts is very simple, and it’s the same as in the persistent scripts.
app.detach_script()