Reportar datos con Frida¶
La función de reporte de datos con Frida se basa en la funcionalidad de persistencia. Puede usar sus scripts de Frida para interceptar automáticamente los datos de las llamadas a métodos y reportarlos a través de nuestro método específico. La función de reporte de datos le permite cargar fácilmente los datos interceptados por el script directamente a Redis o a una interfaz HTTP externa. Puede recibir el contenido de los datos reportados a través de Redis o de la interfaz HTTP. Al mismo tiempo, para maximizar la eficiencia de la red, se admite el reporte de datos después de la compresión (zlib).
Atención
Escribir el script de reporte¶
Primero, necesita modificar su script de Frida. Normalmente, los scripts de Frida tienen funciones como send y log que le permiten enviar datos al exterior. Para FIRERPA, necesita usar un método específico para enviar los datos. A continuación, se muestra un código de plantilla que hemos creado para interceptar el tráfico de okhttp. Es solo un script de demostración y es posible que no pueda usarlo directamente. Este script no es muy diferente de un script convencional; la única diferencia es el uso de un método emit, que es un método incorporado en FIRERPA. A través de él, puede enviar datos al exterior de manera fácil y sistemática.
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
}
})
El método emit tiene dos parámetros: emit(name, content). name representa el tipo de datos. Si la dirección de reporte que ha configurado es Redis, este nombre representa el nombre de la cola de Redis. Debe describirlo en inglés con la mayor precisión posible, como product_info. content representa el contenido de los datos, y los tipos admitidos son solo cadena de texto (string) y arreglo de bytes (bytes). En el ejemplo anterior, lo convertimos en una cadena JSON antes de enviarlo.
Ahora que comprende el formato y los requisitos de llamada para escribir el script, es decir, cómo enviar los datos interceptados (hooked) al exterior, necesita continuar leyendo a continuación para aprender a configurar el destino del reporte de datos.
Destino del reporte de datos¶
El destino del reporte de datos representa a dónde deben enviarse los datos que emite en su script. Los tipos de destino admitidos son interfaces HTTP, colas de Redis y colas de RabbitMQ, con algunas pequeñas diferencias entre ellos.
Normalmente, si no necesita preocuparse por la información del origen de los datos, es decir, no necesita hacer coincidir los datos con la máquina de origen, le recomendamos que utilice una cola de Redis. Por el contrario, debería usar HTTP o MQTT (v5), ya que debido a las características de estos dos protocolos, podemos llevar más metadatos en el protocolo, lo que le permite realizar una coincidencia de dispositivos más precisa.
Metadatos del reporte¶
Para los datos reportados a una interfaz HTTP y a un destino RabbitMQ, además de los datos del reporte original, también puede obtener metadatos sobre el dispositivo y el script a través de la capa de protocolo. Los metadatos incluidos en el protocolo se muestran en la siguiente tabla.
| Campo | Descripción |
|---|---|
| application | Nombre del paquete de la aplicación (ej. com.android.settings) |
| device | ID del dispositivo (ej. 67b2a3d7-5004-ea2a-0d44-194de6ede8de) |
| encode | Codificación de datos (ej. none) |
| name | Nombre de los datos (ej. report_data) |
| script | ID del script (ej. 7c52530d) |
| sequence | Secuencia del reporte (ej. 30) |
| timestamp | Hora del reporte (ej. 1740023596914) |
| user | ID de la aplicación multi-instancia (ej. 0) |
Atención
device es el ID único del dispositivo, que puede encontrar en la barra de información del escritorio remoto. Normalmente, este ID es único y fijo. Puede usarlo para marcar dispositivos y establecer una correspondencia. encode es la codificación de los datos, que admite none y zlib. Si la codificación es zlib, necesitará usar zlib para descomprimir el cuerpo de los datos. name se utiliza para marcar el tipo de estos datos reportados; también es el primer parámetro que utiliza en el método emit. sequence representa el índice de los datos reportados, comenzando desde 0 y aumentando con cada reporte. Puede usar este campo para ordenar los datos o para verificar si se ha perdido algún reporte.
Parámetros adicionales en la URL de reporte¶
Al construir la URL de reporte, puede especificar algunos parámetros de ID dinámicos en la URL. Puede insertarlos en partes específicas de la URL utilizando el formato de placeholder de variable ${name}. Se puede usar en formas como http://192.168.1.2/report/${device_id}. Las variables admitidas son las siguientes.
| Nombre | Descripción del nombre |
|---|---|
| device_id | ID único del dispositivo |
| device_id_short | ID único del dispositivo (ID corto codificado en BASE62) |
| android_id | Android ID |
| serialno | ro.serialno |
Reportar a HTTP¶
Necesitará escribir su propio servicio HTTP para recibir los datos reportados. La interfaz de reporte HTTP debe implementar el método POST. FIRERPA reportará los datos a la interfaz a través de POST y, al mismo tiempo, codificará cada campo de los metadatos como parámetros de consulta HTTP, de los cuales puede extraerlos y procesarlos. El cuerpo de los datos se transporta en el body de la solicitud POST. FIRERPA reintentará automáticamente 3 veces al recibir los códigos de estado 502, 503, 504. Si su backend recibe y procesa correctamente los datos del reporte, debe devolver el texto plano OK o SUCCESS y establecer el código de estado en 200 para indicar un procesamiento exitoso.
Atención
Ejemplo de URL de reporte: http://192.168.1.2/report/${device_id}?serialno=${serialno}
Si se requiere autenticación con contraseña: http://user:password@192.168.1.2/report/${device_id}?serialno=${serialno}
Reportar a MQTT¶
Al reportar a MQTT, debe extraer los metadatos del reporte de UserProperty. Es compatible con TLS, nombre de usuario y contraseña, y validación de certificado unidireccional (verificación del certificado del servidor), pero no admite la verificación bidireccional.
Ejemplo de URL de reporte: mqtt://test.mosquitto.org:1883/script/${device_id}/report
Si se requiere autenticación con contraseña: mqtt://rw:readwrite@test.mosquitto.org:1884/script/${device_id}/report
Si se requiere validación unidireccional: mqtts://test.mosquitto.org:8883/script/${device_id}/report?verify=true&ca=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVBekNDQXV1Z0F3SUJBZ0lVQlkxaGxDR3ZkajROaEJYa1ovdUxVWk5JTEF3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2daQXhDekFKQmdOVkJBWVRBa2RDTVJjd0ZRWURWUVFJREE1VmJtbDBaV1FnUzJsdVoyUnZiVEVPTUF3RwpBMVVFQnd3RlJHVnlZbmt4RWpBUUJnTlZCQW9NQ1UxdmMzRjFhWFIwYnpFTE1Ba0dBMVVFQ3d3Q1EwRXhGakFVCkJnTlZCQU1NRFcxdmMzRjFhWFIwYnk1dmNtY3hIekFkQmdrcWhraUc5dzBCQ1FFV0VISnZaMlZ5UUdGMFkyaHYKYnk1dmNtY3dIaGNOTWpBd05qQTVNVEV3TmpNNVdoY05NekF3TmpBM01URXdOak01V2pDQmtERUxNQWtHQTFVRQpCaE1DUjBJeEZ6QVZCZ05WQkFnTURsVnVhWFJsWkNCTGFXNW5aRzl0TVE0d0RBWURWUVFIREFWRVpYSmllVEVTCk1CQUdBMVVFQ2d3SlRXOXpjWFZwZEhSdk1Rc3dDUVlEVlFRTERBSkRRVEVXTUJRR0ExVUVBd3dOYlc5emNYVnAKZEhSdkxtOXlaekVmTUIwR0NTcUdTSWIzRFFFSkFSWVFjbTluWlhKQVlYUmphRzl2TG05eVp6Q0NBU0l3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFNRTBIS21JemZUT3drS0xUM1RISGUrT2JkaXphbVBnClVabUQ2NFRmM3pKZE5lWUdZbjRDRVhieVA2ZnkzdFdjOFMyYm9XNmR6ckg4U2RGZjl1bzMyMEdKQTlCN1UxRlcKVGUzeGRhL0xtM0pGZmFIamtXdzdqQndjYXVRWmpwR0lOSGFwSFJscGlDWnNxdUF0aE9neFc5U2dEZ1lsR3pFQQpzMDZwa0VGaU13K3FEZkxvL3N4RktCNnZRbEZla01lQ3ltakxDYk53UEp5cXloRm1QV3dpby9QRE1ydUJUelBICjNjaW9CbnJKV0tYYzNPalhkTEdGSk9majdwUDBqL2RyMkxINzJlU3Z2M1BRUUZsOTBDWlBGaHJDVWNSSFNTeG8KRTZ5akdPZG56N2Y2UHZlTElCNTc0a1FPUnd0OGVQbjB5aWRyVEMxaWN0aWtFRDNuSFloTVVPVUNBd0VBQWFOVApNRkV3SFFZRFZSME9CQllFRlBWVjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01COEdBMVVkSXdRWU1CYUFGUFZWCjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUwKQlFBRGdnRUJBR2E5a1MyMU43MFRoTTYvSGo5RDdtYlZ4S0xCalZXZTJUUHNHZmJsM3JFRGZaK09LUloyajZBQwo2cjdqYjRUWk8zZHpGMnA2ZGdicmxVNzFZLzRLMFRkeklqUmozY1EzS1NtNDFKdlVRMGhaL2MwNGlHRGcveFdmCitwcDU4bmZQQVl3dWVycnVQTldtbFN0V0FYZjBVVHFSdGc0aFFEV0J1VUZESlR1V3V1QnZFWHVkejc0ZWgvd0sKc013ZnUxSEZ2ank1WjBpTURVOFBVRGVwalZvbE9DdWU5YXNobFM0RUI1SUVDZFNSMlRJdG5BSWlJd2lteDgzOQpMZFVkUnVkYWZNdTVUNVhtYTE4Mk9DMC91L3hSbEVtK3R2S0dHbWZGY04wcGlxVmw4T3JTUEJnSWxiKzFJS0pFCm0vWHJpV3IvQ3E0aC9KZkI3TlRzZXpWc2xna0Jhb1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
En la URL anterior, los datos relevantes se enviarán a script/${device_id}/report. Puede suscribirse a estos mensajes con un comando como mosquitto_sub -L mqtt://test.mosquitto.org:1883/script/+/report.
Reportar a Redis¶
El reporte a Redis es relativamente simple. Como no lleva ningún metadato, no se puede distinguir directamente el origen de los datos. Es posible que necesite lograr este comportamiento modificando dinámicamente el script inyectado. Para el reporte a Redis, FIRERPA insertará directamente el cuerpo de los datos en la cola mediante LPUSH. Por ejemplo, en el script de ejemplo anterior, los datos del reporte se insertarán en la cola report_data.
Atención
Atención
Ejemplo de URL de reporte: redis://1.2.3.4/0
Si se requiere autenticación con contraseña: redis://:password@1.2.3.4/0
TLS + contraseña
rediss://:password@1.2.3.4/0?ssl_ca_data=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURUVENDQWpXZ0F3SUJBZ0lVUFIvcmcxK0x2aU5tYzNsc0...
Inyectar el script de reporte¶
Por supuesto, obtener la instancia de la aplicación es el primer paso. Puede usar la siguiente llamada para obtener una variable app, que representa la instancia de la aplicación en la que necesita inyectar. Luego, la usará para continuar con las siguientes operaciones de inyección o desvinculación.
app = d.application("com.android.settings")
Use la siguiente interfaz para inyectar el script de reporte mencionado anteriormente en la aplicación. Cuando se intercepten datos, se enviarán a la cola report_data de Redis. En el ejemplo, su dispositivo necesita poder acceder directamente al servicio correspondiente en 192.168.1.10; de lo contrario, no se podrán reportar los datos.
app.attach_script(script, emit="redis://192.168.1.10/0")
También puede configurarlo de esta manera, para que sus datos se envíen a una interfaz HTTP en lugar de a Redis (compatible con https).
app.attach_script(script, emit="http://192.168.1.10/dataReport")
Cuando los datos que reporta son muy grandes, habilitar la compresión puede mejorar significativamente el rendimiento de la transmisión de red. Puede usar encode para habilitar la función de compresión de datos de reporte. Por supuesto, luego también necesitará descomprimir los datos reportados.
app.attach_script(..., encode=DataEncode.DATA_ENCODE_ZLIB)
Descompresión de los datos reportados¶
Por defecto, los datos reportados no tienen ninguna compresión. Si ha configurado la compresión de reporte, también necesitará usar la codificación zlib en el extremo receptor para descomprimir los datos reportados. Puede usar el método decompress de la biblioteca estándar de Python zlib para descomprimir fácilmente los datos reportados.
zlib.decompress(data)
Eliminar el script de reporte¶
El proceso para eliminar el script de reporte es muy simple, es el mismo uso que en los scripts persistentes.
app.detach_script()