使用 Frida 上報資料¶
使用 Frida 上報資料的功能基於持久化功能,您可以透過您編寫的 Frida 腳本自動攔截方法呼叫的資料,並透過我們的特定方法進行資料上報。資料上報功能可以讓您輕鬆地將腳本攔截到的資料直接上傳到 Redis 或外部 HTTP 介面,您可以透過 Redis 或 HTTP 介面接收到上報的資料內容。同時為了最大化網路效能,支援資料壓縮後上報 (zlib)。
注意
編寫上報腳本¶
第一步,您需要改寫您的 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 字串提交。
現在,您已經了解了編寫腳本所需的格式和呼叫要求,也就是如何將 Hook 到的資料提交到外部。您還需要繼續閱讀下文,以了解如何設定資料上報的目的地。
資料上報目的地¶
資料上報目的地,代表您在腳本中 emit 的資料應該傳送到何處。目的地支援的類型有 HTTP 介面、Redis 佇列、RabbitMQ 佇列,它們之間稍有不同。
通常情況下,如果您無需關心資料來源等資訊,即無需將資料與來源機器進行匹配,我們建議使用 Redis 佇列。反之,您則應使用 HTTP 或 MQTT (v5),因為這兩種協定的特性,我們可以在協定中攜帶更多的元資料,讓您可以進行更精確的裝置匹配。
上報的元資料¶
對於上報到 HTTP 介面和 RabbitMQ 目的地的資料,除了包含原始的上報資料外,您還可以透過協定層取得關於裝置及腳本的元資料。協定中附帶的元資料如下表所示。
注意
device 為裝置的唯一 ID,您可以在遠端桌面的資訊欄中找到它,通常這個 ID 是唯一且固定的。您可以透過它來標記裝置,從而建立對應關係。encode 為資料編碼,編碼支援 none 和 zlib。若編碼為 zlib,則您需要使用 zlib 來解壓縮資料主體。name 用來標記此上報資料的類型,它也是您使用 emit 方法時的第一個參數。sequence 代表上報資料的索引,從 0 開始,每次上報都會遞增。您可以透過此欄位對資料進行排序,或檢查是否存在上報遺失的情況。
上報連結的額外參數¶
在您組合上報連結時,支援您在連結中指定一些動態的 ID 參數。您可以透過變數預留位置 ${name} 的格式將其安插在連結的特定位置。透過諸如 http://192.168.1.2/report/${device_id} 的形式使用,支援的變數如下。
上報到 HTTP¶
您需要自行編寫一個接收上報資料的 HTTP 服務,HTTP 上報介面需實作 POST 方法。FIRERPA 將透過 POST 向介面上報資料,同時會將元資料中的各個欄位編碼為 HTTP 查詢參數,您可以從中提取並處理。對於資料主體,則是攜帶在 POST 請求的 body 中。FIRERPA 在收到 502、503、504 狀態碼時會自動重試 3 次。如果您的後端正確接收並處理了上報的資料,應回傳純文字的 OK 或 SUCCESS 並將狀態碼設為 200,以表示處理成功。
注意
範例上報連結 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://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 變數,它代表了您需要注入的應用程式實例,接著您需要透過它來繼續下面的注入或脫離操作。
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()