CydiaSubstrate
絕大部分tweak正常工作的基礎, 它由MobileHooker MobileLoader Safe mode 組成.
MobileHooker
替換系統函式. 也就是所謂的hook, 它主要包含以下兩個函式:
(1) 其中MSHookMessageEx作用於OC函式, 通過呼叫method_setImplementation函式將[class selector] 的實現改為replacement, 達到hook的目的. 如 向一個NSString物件傳送hasSuffix訊息, 而做出hasPrefix的操作, 相當於把函式實現換了.
(2) MSHookFunction : 作用於C和C++函式, 通過編寫彙編指令, 在程式執行到function時轉而執行replacement, 同時保持function的指令及其返回地址, 使得使用者可以選擇性地執行function, 並保證程式能夠在執行完replacement後繼續正常執行. 而且MSHookFunction對function的指令總長度是有要求的, function所有指令加起來長度不能太短.(8位元組)
MSHookFunction三個引數作用分別是: 替換的原函式 替換函式 被MobileHooker儲存的原函式.這個體系寫法如下:
MobileLoader
作用是載入第三方dylib. iOS 啟動時, 會由launchd將MobileLoader載入記憶體, 然後MobileLoader會根據dylib的同名plist檔案指定的作用範圍, 有選擇地在不同程式裡通過dlopen函式開啟目錄/Library/MobileSubstrate/DynamicLibraries/ 下的所有dylib.
Safe mode
由於tweak本質是dylib, 寄生在別的程式裡, 一旦出錯可能會導致程式崩潰, 而如果是SpringBoard等系統程式, 則會造成iOS 系統癱瘓, 所以CydiaSubstrate引入Safe mode, 他會捕獲SIGTRAP SIGABRT SIGILL SIGBUS SIGSEGV SIGSYS這六種訊號, 然後進入安全模式. 安全模式裡所有基於CydiaSubstrate的第三方均會被禁用. 而且這個外掛要自己去安裝, 越獄之後是不會自動安裝的, 所以本人之前的手機就白蘋果了, 如果有這個外掛可以避免一些問題的出現, 不過白蘋果也是可以解決的, 通過iTunes刷機就好了, 還是可以恢復正常的, 但系統就是最新的了.
Cycript
是由saurik推出的一款指令碼語言, 可以看作是Objective-JavaScript .首先ssh到手機的程式, 然後 cycript, 出現cy# 的提示符就說明已成功啟動cycript.
按下control + D , 先退出 Cycript. 如果要測試NSStrign類的 length函式功能, 則可注入任意連線了Foundation庫的程式.
通過程式注入方式呼叫Cycript測試函式的步驟很簡單, 以SpringBoard為例, 首先找到程式名或PID如下:
SpringBoard的程式PID是4634, 接下來輸入 cycript-p 4634 或者 cycript-p SpringBoard, 把Cycript注入到SpringBoard, 這時Cycript已經執行到SpringBoard程式裡了.
如果知道物件的記憶體地址, 還可以通過# 操作符來獲取這個物件.
如果知道物件的記憶體地址, 還可以通過# 操作符來獲取這個物件.
通過choose命令, 可以獲取類物件的地址.
LLDB和debugserver
LLDB
全稱 Low Level Debugger 蘋果出品, 內建Xcode中的動態除錯工具, 執行在Mac中. LLDB功能可以概括以下四點:
(1) 在指定的條件下啟動程式
(2) 在指定的條件下停止程式
(3) 在程式停止的時候對程式進行改動, 觀察程式的執行過程有什麼變化.
(4) 在程式停止的時候檢查程式內部發生的事.
debugserver
執行在iOS 上, 它作為服務端, 實際執行LLDB(客戶端)傳過來的命令, 再把執行結果反饋給LLDB顯示給使用者. 所謂的遠端除錯. 預設iOS 上沒有安裝debugserver, 只有裝置連線過Xcode, 並執行除錯過才會把debugserver安裝到iOS 的 /Developer/usr/bin/ 目錄. 因為缺少task_for_pid許可權,所以只能除錯自己的App.
配置debugserver
1.給debugserver減肥
由於本人用的是iPhone5s所以選擇arm64的架構.
首先將未處理過的debugserver拷貝到電腦中(~/debugserver)這裡可以直接用pp助手.
然後幫助debugserver減肥.
lipo -thin armv7s ~/debugserver -output ~/debugserver
複製程式碼
2.給debugserver新增task_for_pid許可權
下載xml格式檔案配置資訊 iosre.com/ent.xml 到debugserver同級目錄.
然後執行如下命令:
codesign -s - --entitlements ent.xml -f debugserver
複製程式碼
執行前確保xml檔案和debugserver在同一個資料夾內, 而且執行當前命令時要在當前檔案的資料夾中.
如圖:
出現這樣的提示就是成功了.3.然後將處理過的debugserver拷貝到手機中(/usr/bin/)
這裡沒有覆蓋之前的檔案, 一是因為原版檔案是不可寫的, 無法覆蓋, 二是因為/usr/bin/下的命令無須輸入全路徑就可以執行, 即在任何路徑下執行debugserver都可以啟動處理過的debugserver.
最後還要給debugserver賦予執行許可權命令如下:
chmod +x /usr/bin/debugserver
複製程式碼
如果在電腦終端執行必須要ssh到當前手機才可以.
4.用debugserver啟動或附加程式
-
啟動程式
debugserver -x backboard *:1234 /Applications/MobileSMS.app/MobileSMS 複製程式碼
debugserver會啟動MobileSMS, 並開啟1234埠, 等待來自任何IP的LLDB接入.
如果中途出現錯誤, 那麼就有可能是task_for_pid許可權沒加上.
-
附加程式
debugserver *:1234 -a "MobileSMS" 複製程式碼
其實附加程式和啟動程式區別就是需要手動開啟指定的App.
-
錯誤
如果出現如圖:
說明iOS上的/Developer/目錄下缺少必要的除錯資料.因為沒有在Xcode的Window->Devices選單中新增此裝置, 重新新增即可.
LLDB使用說明
在終端中輸入lldb即可啟動lldb. 如圖:
然後執行:
process connect connect://iOSIP:1234
複製程式碼
記得把iOSIP換成自己手機的IP.
成功後如圖:
在這之前debugserver啟動過程式或者附加了程式才可以.
所以電腦終端最好開倆個視窗好操作些, 用手機終端則麻煩很多.
這個時候我們就可以開始除錯了, 下面看一下常用的LLDB命令.
1. image list
用於列舉當前程式中的所有模組, 因為ASLR的關係, 每次程式啟動時(就是當你開啟一個應用時), 同一程式的所有模組在虛擬記憶體中的起始地址都會產生隨機偏移. 個人理解其實就是App啟動時在手機記憶體中是有一個起始的記憶體地址的, 而ASLR其實就是讓App每次開啟時的起始地址隨機.
那麼怎麼獲取模組的起始地址呢? 待LLDB連結debugserver後, 先輸入如下口令:
image list -o -f
複製程式碼
- 模組基地址
上圖的輸出中 第一列 [x] 是模組的序號. 第二列是ASLR產生隨機偏移大小. 第三列是模組的全路徑, 括號裡是偏移之後的起始地址. 模組的起始地址術語叫模組基地址.
偏移後模組基地址 = 偏移前模組基地址 + ASLR偏移
複製程式碼
如上圖MobileSubstrate.dylib的偏移前模組基地址 = 0x0000000104910000 - 0x0000000104910000 = 0
那這個0哪裡來的呢? 我們把MobileSubstrate.dylib放到IDA中.
把View-A拉到最上面看到的第一行, 其中0就是我們計算後的偏移前基地址.
-
符號基地址
偏移後符號的基地址 = 模組ASLR偏移 + 符號基地址
如果是偏移前只要減去ASLR偏移即可.
符號偏移前基地址可以在IDA中根據符號來獲取
只要知道偏移前基地址從IDA看, ASLR偏移從LLDB看就可以了.
2. breakpoint
和Xcode中的斷點一樣, 只不過這裡不是圖形工具而已. 一般逆向工程中用到的:
b function
在函式的起始位置設定斷點
br s –a address
br s –a 'ASLROffset+address'
在地址處設定斷點
複製程式碼
以我自己新建Xocde工程專案設定函式[ViewController buttonAction:]斷點為例:
(1) 用IDA檢視這個專案偏移前的基地址, 把專案二進位制檔案放入IDA中, 定位到buttonAction:方法可以看到:
第一條指令 SUB SP, SP, #0x30 偏移前的基地址是0x100006728.
複製程式碼
(2) 通過LLDB檢視ASLR偏移 0xa8000
(3) 設定並觸發斷點:
指令的偏移後基地址 = 0x100006728 + 0xa8000 = 0x1000ae728
在LLDB中設定斷點
br s -a 0x1000ae728
複製程式碼
其中Breakpoint後面的1是斷點的序號, 以後會用到.
然後我們點選螢幕上的按鈕觸發斷點.
列印的是一些方法的資訊, 當程式停下來後我們可以用c命令繼續執行.
還可以通過br dis 和 br en 和 br del 來禁用 啟用 刪除斷點.
如果是禁用所有斷點則執行
br dis
複製程式碼
禁用某個斷點在後面加上斷點的序號
br dis 1
複製程式碼
同理啟用和刪除斷點也是一樣.
br en
br del
複製程式碼
另外一個很有用的命令就是在斷點觸發前執行預先設定的指令, 它的用法如下:
br com add 1
複製程式碼
然後出現如圖:
其中po i 是要執行的指令, 而DONE是退出設定指令. 數字4是斷點的序號.
這裡設定了一條指令, 然後我們點選按鈕觸發方法如圖:
這個時候i的值是1.
這個命令一般用於自動觀察某個斷點觸發時的上下文變化, 後面會用到.
3. print
LLDB主要功能之一是在程式停止的時候檢查程式內部發生的事, 而這個功能是通過print命令完成的, 他可以列印某處的值. 以我本人最近開發的程式 -[HomePageController tableView:didSelectRowAtIndexPath:] 方法為例演示一系列用法.
po $r0 輸出r0對應的值
p $r0 輸出r0值的型別以及命令結果
p/x $r0 輸出r0的十六進位制值
x/10 $r0 輸出指標r0指向的連續10個字的資料
nexti(ni) 執行下一條機器指令 不會進入函式體
stepi(si) 執行下一條機器指令 會進入函式體
** 進不進入函式體的意思就是你再方法中呼叫其他方法, 而當斷點到這個方法的時候, 如果是上面的指令會跳轉的這個呼叫的方法裡面, 而下面的指令不會進入. **
register write r0 1 給暫存器r0賦值為1
複製程式碼