# 持久化 Frida 腳本

FIRERPA 為您提供了持久化 Frida 腳本的能力，您可以透過相關介面便捷地注入腳本，FIRERPA 的腳本管理器會自動為您管理注入的腳本。即使您的腳本異常退出或 APP 行程退出，FIRERPA 仍然會在您的 APP 下次開啟時自動為您重新注入腳本。此功能於 7.80 版本引入。

## 安裝腳本

您可以使用此介面來將您的腳本安裝到相關應用程式，您安裝到該應用程式的腳本將會在安裝後立即注入相關應用程式。安裝的腳本會自動進入腳本管理器，管理器將會為您時刻監控並重新注入。

```{attention}
腳本管理器同時只允許每個 APP 注入一個腳本，您無法對相同應用程式一次注入多個腳本。
```

```python
app = d.application("com.android.settings")
app.attach_script(script, runtime=ScriptRuntime.RUNTIME_QJS, standup=5)
```

`script` 參數為您需要注入的 Frida 腳本內容（支援位元組碼），`runtime` 為對應的 runtime，預設為 `qjs`，`standup` 參數的意義為僅當 APP 行程啟動 5 秒後才進行注入（時間從行程建立開始計算），此參數最低為 1 秒，最高為 300 秒，以避免過早注入應用程式行程而引起崩潰等其他的競爭條件問題，在 spawn 模式時，該參數應始終為 0。

此介面也支援 spawn 模式注入，但請注意，使用 spawn 模式可能會中斷您的 UI 操作流程（如果您需要同時操作 UI 的話），因為一旦您使用 spawn 模式，在注入腳本異常或應用程式退出的情況下，該模式會自動重新喚起應用程式，從而對您的介面操作產生干擾。如果您需要使用 spawn 模式，請使用如下參數。

```python
app = d.application("com.android.settings")
app.attach_script(script, runtime=ScriptRuntime.RUNTIME_QJS, spawn=True, standup=0)
```

需要注意 spawn 模式與普通模式有區別，在普通模式下，如果應用程式因某些原因退出，普通模式將會一直等到應用程式啟動才會執行注入，不會擅自啟動應用程式，因此可能需要您自行透過程式碼或手動方式啟動應用程式才會繼續注入。而在 spawn 模式下，即使應用程式退出，也會自動啟動應用程式並執行注入。

## 取消安裝

本介面將會移除已安裝在應用程式中的 Frida 腳本，該腳本也將從應用程式行程中脫離，同時 FIRERPA 的腳本管理器也將不再監控該腳本的健康狀態，也不會在腳本異常後繼續進行重新注入等相關操作。

```python
app = d.application("com.android.settings")
app.detach_script()
```

## 檢查是否已安裝

本介面用於檢查判斷應用程式是否已經安裝了腳本，您可以根據此狀態檢查是否需要重新安裝。

```python
app = d.application("com.android.settings")
app.is_attached_script()
```

## 檢查是否已注入

本介面用於檢查您安裝的腳本當前是否已經注入應用程式行程，因為即使您執行了腳本安裝，由於應用程式可能尚未啟動或腳本錯誤，導致腳本並未注入到應用程式行程，您可以根據其回傳值判斷是否需要啟動相關應用程式或檢查注入腳本是否存在語法錯誤。

```python
app = d.application("com.android.settings")
app.is_script_alive()
```

## 查看腳本日誌

您腳本中的 `console.log` 等相關主控台日誌以及腳本的錯誤訊息均可查看，但您需要提前在啟動時進行設定，請查看 `查看日誌` 章節以了解如何設定日誌檔案。下面我們假設您已正確設定日誌檔案為 `/data/local/tmp/server.log`。這樣，在需要查看腳本日誌時執行以下指令，這將過濾出所有注入腳本的日誌資訊，您也可以透過 `tail -f` 等其他指令來持續追蹤日誌。

```bash
grep SCRIPT /data/local/tmp/server.log
```

## 離線持久化

離線持久化是指您可以將您的 FRIDA 腳本作為設定檔放置到手機上，在 FIRERPA 啟動後會自動載入您的 FRIDA 腳本。您完全不需要使用上述 API 介面來進行注入、取消等操作，只需要將腳本檔案以特定格式編寫並放到固定目錄即可。此功能支援目錄監控，可即時載入、卸載及更新腳本。在腳本目錄中直接編輯修改也會即時套用。以下是一個簡單的 YAML 腳本持久化設定，下面這個設定的腳本內容是 `console.log("Hello From Yaml Script")`。

```yaml
enable: true
application: "com.android.settings"
version: "2.10"
user: 0
runtime: "qjs"
script: !!binary "Y29uc29sZS5sb2coIkhlbGxvIEZyb20gWWFtbCBTY3JpcHQiKQ=="
emit: "http://myserver/reportData"
encode: "none"
standup: 10
spawn: false
```

上述範例腳本設定中每個設定項的詳細解釋

| 欄位        | 描述                                                                |
|-------------|---------------------------------------------------------------------|
| enable      | 是否啟用此腳本                                                      |
| application | 注入腳本的應用程式 ID（例如 com.android.setting）                   |
| version     | 注入腳本支援的應用程式版本（"N/A" 代表不限版本）                    |
| user        | 如果是多開應用程式，請指定為多開應用程式的使用者 ID（通常為 999）   |
| script      | 腳本內容 base64，支援文字或二進位（請按照範本編寫）                 |
| runtime     | 腳本 runtime（qjs、v8）                                             |
| standup     | 延遲注入的時間（從行程啟動時間計算）                                |
| spawn       | 使用 spawn 模式（將會忽略 standup）                                 |
| encode      | 如果腳本存在資料上報，在此指定編碼（zlib/none）                     |
| emit        | 如果腳本存在資料上報，在此指定目的                                  |

更多關於 emit 資料上報功能，請查看 `使用 Frida 上報資料` 章節。

以上是一個完整的離線腳本範例，編寫完成後，請將上述內容的設定檔儲存為名為 `{file_name}.yaml` 的檔案，並放置到裝置的 `/data/usr/modules/script` 資料夾，系統將會自動載入您的設定。系統會自動偵測 `/data/usr/modules/script` 目錄的變動，如果您更新或刪除了 yaml 設定，系統也會自動更新或取消注入您的腳本。