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 ,或者使用我們提供的 frida_script_generate.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)
device設備 ID (如 67b2a3d7-5004-ea2a-0d44-194de6ede8de)
encode資料編碼(none
name資料名稱(如 report_data)
script腳本 ID(如 7c52530d)
sequence上報順序(如 30)
timestamp上報時間(如 1740023596914)
user多開應用 ID(如 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(BASE62 編碼的短設備ID)
android_id安卓 ID
serialnoro.serialno

上報到 HTTP

您需要自行編寫一個接收上報資料的 HTTP 服務,HTTP 上報介面需實作 POST 方法。FIRERPA 將透過 POST 向介面上報資料,同時將會把元資料中的各個欄位編碼為 HTTP 查詢參數,您可以從中提取並處理。對於資料本體,則是攜帶在 POST 請求的 body 中。FIRERPA 會在收到 502、503、504 狀態碼時自動重試 3 次,如您的後端正確接收並處理了上報資料,應返回純文字的 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 佇列中。

注意

只支援單例模式(standalone)的 Redis 服務,不支援 Redis 叢集。除了密碼欄位,請勿在 Redis 連結中加入變數佔位符。連結為標準 Redis 庫支援的格式,修改其他部分可能導致無法正確解析。

範例上報連結

redis://1.2.3.4/0

需要密碼認證的 Redis

redis://:password@1.2.3.4/0

TLS + 密碼認證的 Redis

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

注入上報腳本

當然,獲取 app 實例是第一個步驟,您可以透過上述調用來獲取一個 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 編碼來對上報資料進行解壓縮。您可以使用 Python 官方庫 zlib 的 decompress 方法方便地對上報資料進行解壓。

zlib.decompress(data)

移除上報腳本

移除上報腳本的過程很簡單,和持久化腳本裡的用法是一樣的。

app.detach_script()