Отправка данных с помощью Frida

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

Внимание

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

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

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

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

Назначение отправки данных

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

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

Метаданные отправки

Для данных, отправляемых в HTTP-интерфейс или в MQTT, помимо самих отправляемых данных вы можете получить на уровне протокола метаданные об устройстве и скрипте. Метаданные, передаваемые в протоколе, приведены в таблице ниже.

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

Внимание

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

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

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

Вы можете задавать в ссылке отправки некоторые динамические параметры идентификаторов, вставляя их в определённые части ссылки в формате переменных-заполнителей ${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:

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 с аутентификацией по паролю:

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 с аутентификацией по паролю:

redis://:password@1.2.3.4/0

Redis с TLS и аутентификацией по паролю:

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

Внедрение скрипта отправки

Разумеется, первым шагом является получение экземпляра приложения. С помощью описанного выше вызова вы можете получить переменную 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")

При таком вызове ваши данные будут отправляться в 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()