tidevice 開啟 iOS16 Developer Mode 的功能開發過程

codeskyblue發表於2023-01-16

tidevice 簡介

tidevice 是一個專注於與 iOS 裝置做互動的測試工具
連結 https://github.com/alibaba/taobao-iphone-device

以前沒寫過怎麼做 tidevice 的開發的文章,不過猜測應該會有不少人喜歡看吧,所以趁著這次給 iOS 加新功能的契機,記錄一下開發流程供想提 pr 的人參考一下吧。

背景

從 iOS16 開始,iPhone 的開發者模式就需要手工開啟了。
根據蘋果官網提供的資料,需要手機連線 Xcode,然後才會出現開發者模式的開關。所以可以猜測,Xcode 肯定是傳送了什麼資料到手機。下面的步驟就是介紹怎麼捕獲到這些資料。

捕獲和分析資料用到的工具
go-ios、vscode、一臺蘋果電腦
簡單介紹一下go-ios,這個是用 go 語言寫的一個同 iPhone 進行資料互動的一個工具,跟 tidevice 的功能比較類似,甚至功能還更多一點。它自帶的這個抓包功能非常的好用,所以就直接拿來用了。

git clone https://github.com/danielpaulus/go-ios
cd go-ios
# 沒有安裝go環境,可以去官網go.dev下載開發環境
go build
# Output binary: ./go-ios

抓包之前提前關閉 Xcode

抓包

  1. 使用 root 許可權啟動抓包程式 sudo ./go-ios dproxy
  2. 啟動 Xcode,隨便開啟一個專案。這裡選中手機

  1. 然後手機 設定->隱私與安全性->螢幕滾動到最後,看到開發者模式,就算是可以了。
  2. Ctrl-C 停掉 go-ios 程式。捕獲到資料全部都儲存到了 dump-<時間戳> 的資料夾下面.
  3. 修改一下剛捕獲資料的許可權 sudo chown -R $(whoami) dump-* ## 分析資料 使用 vscode 開啟資料夾 dump-<時間戳> 會看到裡面有很多 connection-開頭的資料夾,每一個資料夾裡面的資料都代表一次連線包含的資料。 實在太多了,有沒有感覺。100 多個資料夾。我在裡也沒有什麼太好的辦法了,一個個的看過去吧。 開啟其中一個檔案的時候發現應該是的,後來證明確實是的(如果不是的話,就繼續看,知道找到為止) 熟練一些的話,可以用一些指令碼過濾出來可能得請求。 比如可以用下面的程式碼過濾出來所有 StartService 的程式碼 $ find . -name "jsondump.json" | xargs cat | grep -v PairRecordData | grep StartService ... 結果省略 ...

經過仔細的人工排查,發現其中一個 connection 的可能性比較高:啟動了 Service "com.apple.amfi.lockdown" 這部分的程式碼

程式碼啟動了 Service "com.apple.amfi.lockdown",裝置返回連線埠號 49304
但是直接全文搜尋 49304 卻搜尋不到,這個其實跟 go-ios 儲存的結構有關係。需要做一下轉化

49304 = 0xc098

#LittleEndian to BigEndian
0x98c0 = 39104

# Unsigned int to signed int16
2**16 - 39104 = 26432

用 Python 也可以很快的算出來2**16 - socket.htons(49304)

搜尋 26432 就可以找到對應的檔案了。然後看到 jsondump.json 並沒有多少內容,定位到檔案所在的目錄,發現裡面還有兩個檔案

connection-#107-2023.01.16-03.28.19.046
|-- bindump-hostservice-to-proxy.txt
|-- from-device.bin
|-- jsondump.json
`-- to-device.bin

為了檢視 bin 檔案的內容,Vscode 安裝個外掛 Hex Editor
開啟 to-device.bin 就可以看到下面的內容

這個結構相當簡單,大概猜一下就出來了。
前 4 個位元組代表整個檔案的長度。後面接下來的 body 一看就是 plist 編碼的。可以用程式碼解析一下里面的內容

import plistlib

raw = open("to-device.bin", "rb").read()
payload = plistlib.loads(raw[4:])
print(payload)
# 輸出
# {'action': 0}

然後 device 返回了的內容在 from-device.bin 中可以查到

00 00 00 D9

這幾個位元組也看不出來啥意思,估計就是成功的 code 吧。

程式碼實現

流程差不多理清楚了,用程式碼模擬一下

import tidevice
import plistlib
import struct

d = tidevice.Device()
conn = d.start_service("com.apple.amfi.lockdown")
body = plistlib.dumps({"action": 0})
head = struct.pack(">I", len(body))
conn.psock.sendall(head+body)
conn.psock.recv() # read until connection closed

看起來沒問題了,程式碼封裝成函式就行了。
本次 tidevice 的具體更新內容如下
https://github.com/alibaba/taobao-iphone-device/compare/0.9.14...0.10.1

參考連結

  • https://developer.apple.com/documentation/xcode/enabling-developer-mode-on-a-device
  • https://github.com/danielpaulus/go-ios

相關文章