Использование Frida для отправки данных

Функция отправки данных с помощью Frida основана на механизме персистентности. Вы можете использовать написанный вами скрипт Frida для автоматического перехвата данных вызовов методов и их отправки с помощью нашего специального метода. Эта функция позволяет легко загружать перехваченные скриптом данные напрямую в Redis или на внешний HTTP-интерфейс. Вы можете получать отправленные данные через Redis или HTTP-интерфейс. Кроме того, для максимальной эффективности сети поддерживается отправка данных после сжатия (zlib).

Внимание

Начиная с версии 9.0, используемая нами по умолчанию Frida 17.x требует самостоятельной упаковки `frida-java-bridge` в скрипт, иначе возникнут ошибки, связанные с `Java not defined`. Это изменение внесено официально разработчиками Frida. Согласно их инструкциям, вам необходимо создать новый проект Node.js и подключить java bridge. Подробности см. на https://github.com/oleavr/frida-agent-example или используйте наш инструмент `tools/frida_script_generate.py` для повторной упаковки исходного JS-скрипта.

Написание скрипта для отправки данных

Первый шаг — это изменение вашего скрипта 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). name представляет тип данных. Если в качестве адреса для отправки указан Redis, то это имя будет именем очереди Redis. Старайтесь давать точное описание на английском языке, например, product_info. content представляет содержимое данных, поддерживаются только типы строка (string) и массив байтов (bytes). В приведенном выше примере мы преобразовали данные в строку JSON перед отправкой.

Теперь, когда вы ознакомились с форматом и требованиями к вызовам для написания скрипта, то есть как отправлять перехваченные данные вовне, вам необходимо прочитать далее, чтобы узнать, как настроить место назначения для отправки данных.

Место назначения для отправки данных

Место назначения для отправки данных определяет, куда должны отправляться данные, переданные через emit в вашем скрипте. Поддерживаются следующие типы мест назначения: HTTP-интерфейс, очередь Redis, очередь RabbitMQ. Между ними есть некоторые различия.

Обычно, если вам не нужно беспокоиться об источнике данных, то есть нет необходимости сопоставлять данные с исходным устройством, мы рекомендуем использовать очередь Redis. В противном случае вам следует использовать HTTP или MQTT (v5), так как особенности этих протоколов позволяют нам передавать больше метаданных, что обеспечивает более точное сопоставление с устройствами.

Отправляемые метаданные

При отправке данных на HTTP-интерфейс или в RabbitMQ, помимо исходных данных, вы также можете получить метаданные об устройстве и скрипте на уровне протокола. В протоколе передаются следующие метаданные:

ПолеОписание
applicationИмя пакета приложения (например, com.android.settings)
deviceID устройства (например, 67b2a3d7-5004-ea2a-0d44-194de6ede8de)
encodeКодирование данных (например, none)
nameИмя данных (например, report_data)
scriptID скрипта (например, 7c52530d)
sequenceПорядковый номер отправки (например, 30)
timestampВремя отправки (например, 1740023596914)
userID экземпляра приложения (например, 0)

Внимание

Из-за особенностей протокола Redis, данные, отправляемые в Redis, не содержат вышеуказанных метаданных.

device — это уникальный ID устройства, который вы можете найти в информационной панели удаленного рабочего стола. Обычно этот ID уникален и постоянен. Вы можете использовать его для маркировки устройств и установления соответствий. encode — это кодирование данных, поддерживаются none и zlib. Если кодирование — zlib, вам потребуется использовать zlib для распаковки тела данных. name используется для маркировки типа отправляемых данных, это также первый параметр метода emit. sequence представляет собой индекс отправляемых данных, начиная с 0, который увеличивается при каждой отправке. Вы можете использовать это поле для сортировки данных или проверки наличия потерь при отправке.

Дополнительные параметры в ссылке для отправки

При формировании ссылки для отправки вы можете указать в ней некоторые динамические параметры ID. Вы можете вставить их в определенные части ссылки, используя формат заполнителя ${name}. Например, в виде http://192.168.1.2/report/${device_id}. Поддерживаются следующие переменные:

ИмяОписание
device_idУникальный ID устройства
device_id_shortУникальный ID устройства (короткий ID в кодировке BASE62)
android_idAndroid ID
serialnoro.serialno

Отправка по HTTP

Вам необходимо самостоятельно написать HTTP-сервис для приема отправляемых данных. Интерфейс для отправки данных по HTTP должен реализовывать метод POST. FIRERPA будет отправлять данные через POST, при этом поля метаданных будут закодированы как параметры запроса HTTP, из которых вы сможете их извлечь и обработать. Тело данных передается в теле POST-запроса. FIRERPA автоматически выполнит 3 повторные попытки при получении кодов состояния 502, 503, 504. Если ваш бэкенд правильно принял и обработал данные, он должен вернуть чистый текст OK или SUCCESS и установить код состояния 200 для подтверждения успешной обработки.

Внимание

HTTP-запросы являются многопоточными, поэтому сообщения, полученные бэкендом, могут не соответствовать порядку отправки (sequence).
Пример ссылки для отправки 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, имя пользователя и пароль, а также односторонняя проверка сертификата (проверка сертификата сервера), двусторонняя проверка не поддерживается.

Пример ссылки для отправки 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

В приведенной выше ссылке соответствующие данные будут отправлены в топик script/${device_id}/report. Вы можете подписаться на эти сообщения, например, с помощью команды mosquitto_sub -L mqtt://test.mosquitto.org:1883/script/+/report.

Отправка в Redis

Отправка в Redis относительно проста. Поскольку она не несет никаких метаданных, невозможно напрямую различить источник данных. Вам может потребоваться реализовать это поведение путем динамического изменения внедряемого скрипта. При отправке в Redis FIRERPA будет напрямую помещать тело данных в очередь с помощью команды LPUSH. Например, в скрипте-примере из предыдущего раздела данные будут помещены в очередь report_data.

Внимание

Поддерживаются только Redis-серверы в автономном режиме (standalone), кластеры Redis не поддерживаются.

Внимание

Кроме поля пароля, не используйте заполнители переменных в ссылке на Redis. Ссылка соответствует стандартному формату, поддерживаемому библиотеками Redis, и изменение других частей может привести к неправильному парсингу.
Пример ссылки для отправки 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 = d.application("com.android.settings")

С помощью следующего интерфейса внедрите вышеупомянутый скрипт в приложение. При перехвате данных они будут отправлены в очередь report_data в Redis. В этом примере ваше устройство должно иметь прямой доступ к соответствующей службе на 192.168.1.10, иначе отправка данных не удастся.

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

Вы также можете настроить это следующим образом, и тогда ваши данные будут отправляться на HTTP-интерфейс, а не в Redis (поддерживается https).

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

Когда вы отправляете большие объемы данных, включение сжатия может значительно повысить пропускную способность сети. Вы можете использовать encode для включения функции сжатия отправляемых данных. Конечно, вам также потребуется выполнить операцию распаковки полученных данных.

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

Распаковка отправленных данных

По умолчанию отправляемые данные не сжимаются. Если вы включили сжатие, вам необходимо на принимающей стороне использовать кодировку zlib для распаковки данных. Вы можете легко распаковать данные с помощью метода decompress из стандартной библиотеки Python zlib.

zlib.decompress(data)

Удаление скрипта для отправки данных

Процесс удаления скрипта очень прост и аналогичен использованию в скриптах персистентности.

app.detach_script()