上一篇文章 iOS 逆向 - LLDB 中講述了 lldb
的一些基礎用法 , 並無涉及太多其餘內容 , 逆向過程當中經常使用的動態調試方法其實還有一些 , 本文針對上篇文章和實際逆向中的運用進行一個補充 .git
主要針對 Chisel
以及 Cycript
兩個部分 .github
若是篇幅不長 , 咱們來說一講自定義 cy
指令.shell
有部分同窗反應重簽名微信應用被封號的狀況 . 這裏說明一下 , 微信 / 抖音 等應用是有防禦和監測操做的 , 網上流傳部分破解微信防禦的 logos
代碼 , 筆者測試效果不是百分百 , 有須要的小夥伴能夠評論留言 .vim
調試別人應用自己是會形成相似問題的 , 所以儘可能不要登陸我的使用帳號 , 如非必須登陸 , 不要登陸帳號 .ruby
確實須要登陸 , 登陸一個小號 , 另外提早準備好另外一個帳戶去解封 .bash
在越獄環境下 , 使用插件的方式調試 , 無須重簽名 , 被封號的概率是很低的 .微信
最後再強調一次 : 玩逆向只是爲了更好地防禦 .app
Chisel 也是 Facebook
發佈的一個 lldb
的插件 , 可以作到幫助調試和提供用戶自定義指令集的功能 . 接下來會具體闡述 .函數
命令 : brew install chisel
工具
( 尚未安裝 HomeBrew 的自行安裝 )
安裝後使用 : brew list
查看安裝結果
如何配置 ?
cd /usr/local/Cellar/chisel
open .
, 找到 fblldb.py
腳本文件.
cmd + opt + c
拷貝文件路徑..lldbinit
文件 , 請查閱上一篇文章 iOS 逆向 - LLDB 中最後講自動啓用加載指令所述 , 使用 vim
自行建立便可 .
vim .lldbinit
s
進入編輯模式command script import /usr/local/Cellar/chisel/1.8.1/libexec/fblldb.py
( 路徑換成你本身的 )
ESC
, :wq
保存退出先來簡單試一下配置成功了沒 .
注意 : 若是是正在運行的工程 , 那你須要使用 command source ~/.lldbinit
, 來從新加載一下 lldb
配置文件 .
隨便打開一個工程 , 進入斷點模式 , 輸入 pviews
.
pviews
就是 Chisel
提供的一個查看視圖層級的命令 . 以上看到 , 咱們已經配置成功了 .
爲了模擬逆向過程當中實際動態調試場景 . 我使用了我以前使用 MonkeyDev
重簽名的微信應用來演示指令 , 對重簽名不熟悉的同窗能夠閱讀一下 重籤應用調試與代碼修改 (Hook) , 與 shell 腳本自動重簽名與代碼注入 , 這兩篇文章 .
MonkeyDev
的安裝和使用咱們就很少贅述了 , 畢竟重簽名原理理解了 , Monkey
其本質上也是利用腳本自動重簽名 , 而後 代碼注入 hook
部分集成了 Cydia Substrate
來作的.
咱們所須要作的只是把砸過殼的 ipa
或者 app
包 放到指定文件夾下便可完成重簽名和代碼注入 . 很是方便.
若是同窗們關於 MonkeyDev
使用有問題能夠留言告知 .
運行工程 .
打開註冊頁面 , 暫停 . 進入斷點模式 ,
pviews
pviews
能夠幫助咱們很清楚的看出圖層邏輯層級關係以及內存地址 .指令 : pvc
結果 :
說明 : pvc
能夠幫助咱們很清楚的看出視圖控制器層級關係以及內存地址 .
使用 pviews
, 隨便找到一個按鈕 , 複製其內存地址 .
pactions 0x10b06e5e0
pactions
能夠拿到 button
的 target
以及 action
, 在逆向時須要方法 hook
常常會使用.使用 pviews
, 隨便找到一個按鈕 , 複製其內存地址 .
presbonder 0x10b06e5e0
presbonder
能夠查看完整的響應鏈.使用 pclass
, 隨便找到一個類 , 複製其內存地址 .
pclass 0x10b910600
pclass
能夠查看完整的繼承鏈.pclass 0x106b57bc0
pmethods
能夠查看類完整的類方法和實例方法.pinternals 0x10b660df0
fvc -v 0x10b8fe000
fvc
, 視圖用 fv
.fv + 類名
反之是同樣的 , 回去工程搜索這個類 打印其內存地址 .taplog
taplog
輸入後會退出斷點模式 , 再點擊屏幕上任何可響應視圖 , 會自動進入 lldb
模式並打印按鈕.flicker 0x11827c040
view
, 很是方便調試 , 以及肯定該內存地址是否爲咱們想找到的那個視圖 .vs 0x11827c040
(lldb) vs 0x1120f3390
Use the following and (q) to quit.
(w) move to superview // 來到當前視圖的父視圖
(s) move to first subview // 來到當前視圖的第一個子視圖
(a) move to previous sibling // 來到當前視圖同級關係下的前一個視圖
(d) move to next sibling // 來到當前視圖同級關係下的後一個視圖
(p) print the hierarchy // 打印當前視圖的層級結構
<FixTitleColorButton: 0x1120f3390; baseClass = UIButton; frame = (20 112; 374 47); clipsToBounds = YES; opaque = NO; autoresize = W; layer = <CALayer: 0x1118c0900>>
複製代碼
q
指令 .最後三條指令在逆向過程當中很是經常使用 , 你們多加練習與掌握 .
這個 LLDB
插件叫 lldb_commands
. 地址爲 github.com/DerekSeland…
Clone
或者下載 , 把 lldb_commands
文件夾保存起來 , 我這邊是放到 /usr/local/Cellar
裏.lldbinit
, 添加一條指令 :command script import /usr/local/Cellar/lldb_commands/dslldb.py
複製代碼
路徑換成本身的 lldb_commands
文件夾路徑便可 .
工程來到 lldb
模式下 , 輸入 search UIView
, 便可測試有沒有配置成功 .
找到視圖控制器地址 , 使用 methods 查看其全部的實例方法和屬性 .
注意 : 因爲逆向時 方法的符號是沒有恢復的 , 所以根據類名和方法名下斷點會失敗 .
因爲符號並無恢復 , 所以 bt
指令查看函數調用棧時 , 會出現如下狀況 .
( 後續會講如何利用工具恢復 Mach-O 的符號 )
那麼此時 , 利用 lldb_commands
提供的 sbt
指令 , 會幫助恢復一些符號 , 以便於查看方法名稱 .
Section
指令可讓咱們快速查看 Mach-O
有哪些 Section
段 .
Section
可添加其餘指令來查看 Mach-O
具體內容 .# Dump the Mach-O segments to the main executable
(lldb) section
# Dump the Mach-O segments to UIKit
(lldb) section UIKit
# Dump the Mach-O sections of the __TEXT segment of UIKit
(lldb) section UIKit __TEXT
# Get the load address of all the hard-coded uint8_t * strings in the UIKit binary
(lldb) section UIKit __TEXT.__cstring -l
# Get the entitlements for the executable (simulator only, entitlements for actual app in __LINKEDIT)
(lldb) section __TEXT.__entitlements
# Get all the load address to the lazy symbol stubs in the main executable
(lldb) section __DATA.__la_symbol_ptr -l
複製代碼
效果以下 , 你們能夠結合 MachOView
來查看結果.
Cycript 是由 Cydia
( 熟悉越獄的同窗應該都很清楚 ) 創始人 Saurik
推出的一款腳本語言,Cycript
混合了 OC
、 JavaScript
語法的解釋器,這意味着咱們可以在一個命令中使用 OC
或者 JavaScript
,甚至二者並用。
它可以掛鉤 正在運行的進程,可以在運行時修改不少東西。
到官網點擊 Download SDK
便可下載 .
/opt/
裏便可 , 也能夠自行選擇位置 .
zsh
仍是 bash
去相應的資源文件配置 (家目錄下的 .zshrc
/ .bash_profile
) ..zshrc
中也配置了 bash_profile
的引用 , 所以兩處來配置這個環境變量都是能夠的.
配置內容:
export CY=/opt/cycript_0.9.594/
, 換成你本身的路徑.:$CY
重啓 iTerm
, 輸入 cycript
, 便可查看 .
若是有遇到 ruby
環境不對的同窗 , 去下載對應版本的便可 . /System/Library/Frameworks/Ruby.framework/Versions
在越獄環境下 , 是能夠在 Cydia
直接安裝 Cycript
插件的.
越獄手機截圖上傳有點麻煩 , 直接拍的.. 瑕疵請忽略 , 看個意思
那麼非越獄環境下 , 就要藉助 Cycript
提供的 iOS Framework
, 注入進去了 . 並且在 MonkeyDev
中 , 是默認已經作好了 Cycript
的注入的 .
並且添加了 默認 6666
端口號的監聽 .
也就是說只要用 MonkeyDev
來重籤跑起來的程序進程 , 6666
端口就能夠附加使用了 ( 固然 , 在 Monkey
裏代碼能夠本身定義端口號 ) .
好了 說了這麼多 , 開始使用.
MonkeyDev
重簽名程序 / 或者直接打開之前重簽好的工程 , 無須 Xcode
運行也能夠cycript -r 192.168.0.116:6666
ip
地址出現如下 , Congratulations , you're good to go !
使用 tab
鍵 , 寫代碼能夠補全 .
查看當前 Window
.
指令 : [UIApplication sharedApplication ]
可簡寫爲 UIApp
指令 : 本身 var
一個對象 , 然後咱們就可使用 .
另外注意 : 只要 APP
進程沒有掛 , 這個變量是一直存在的 .
#
+ 對象地址 能夠直接調用對象的方法
UIWindow.keyWindow().recursiveDescription().toString()
隨便找一個 , 例如註冊頁面有一個 .text
爲 +86
的 label
, 拿到其內存地址 ,
命令 :
#0x10b95d800.text = "hhh"
複製代碼
顯示結果
基於這種直接修改進程內存的方式 , 你們能夠本身去玩一玩 . 好比登陸了修改一下錢包餘額 , 而後改一改 frame
, 練習一下 .
如下指令結果我就不一一貼圖了 , 文章太長 , 不便閱讀 , 你們本身嘗試 .
choose(UIButton)
choose(UILabel)
[UIApp setStatusBarHidden:YES]
[UIApp setApplicationIconBadgeNumber: 99]
APPID
結果 :
@"com.libin.LBMonkeyApp"
pviews()
pvcs()
pactions (#0x10b29da40)
結果 :
"<WCAccountRegisterViewController: 0x10b9d9800> onAgreementCheckBoxClick:"
複製代碼
rp(#0x10b29da40)
control
+ d
pviews
/ pvc
/ pactions
/ rp
這些指令是 Monkey
在 MDConfig.plist
中額外封裝了自定義的 cy
源的 . 也就是說使用越獄環境本來的 cycript
插件是沒有這些指令可用的 .
那麼咱們閒着也是閒着 , 咱們也來本身寫一個 cy
源來玩一下 ?
在咱們的 monkey
工程主工程 target
中新建一個空文件, 我這裏取名 lb.cy
.
Build Phases
- Copy Files
, 引入這個文件
在空文件添加咱們想本身定義的指令 . 能夠參照 Monkey 本來提供的那兩個來寫 raw.githubusercontent.com/AloneMonkey…
這裏我寫了一些我經常使用的指令 , 好比獲取 APPID
/ APPPATH
, 當前跟視圖 , 當前頁面 這些 , 我貼在下面供你們參考 , 也能夠拿去直接用 .
從新運行工程 .
輸入咱們自定義的指令 例如 : LBCurrentVC()
提示沒找到指令 , 由於咱們尚未引入 , monkey
那兩個在 config
中會自動引入.
@import lb
再次輸入 LBCurrentVC()
, 獲得結果.
//IIFE 匿名函數自執行表達式
(function(exports){
APPID = [NSBundle mainBundle].bundleIdentifier,
APPPATH = [NSBundle mainBundle].bundlePath,
//若是有變化,就用function去定義!!
LBRootvc = function(){
return UIApp.keyWindow.rootViewController;
};
LBKeyWindow = function(){
return UIApp.keyWindow;
};
LBGetCurrentVCFromRootVc = function(rootVC){
var currentVC;
if([rootVC presentedViewController]){
rootVC = [rootVC presentedViewController];
}
if([rootVC isKindOfClass:[UITabBarController class]]){
currentVC = LBGetCurrentVCFromRootVc(rootVC.selectedViewController);
}else if([rootVC isKindOfClass:[UINavigationController class]]){
currentVC = LBGetCurrentVCFromRootVc(rootVC.visibleViewController);
}else{
currentVC = rootVC;
}
return currentVC;
};
LBCurrentVC = function(){
return LBGetCurrentVCFromRootVc(LBRootvc());
};
})(exports);
複製代碼
使用 cycript
某一個控件 / 對象 內存地址時 , 要注意其生命週期 , 例如用一個 label
的內存地址調試 , 你頁面退出 , 又重進 , 是從新建立了對象的 , 之前的內存地址也會沒法再使用 . 不要忘記這點 .
cycript
使用須要同局域網每次要鏈接 , 或者其餘咱們須要自定義的初始化動做 , 咱們能夠將其寫到一個腳本中 , 配置到 zsh
/ bash
環境變量中便可 , 你們能夠玩一玩 , 有問題你們一塊兒探討一下 .
逆向過程當中 , View Debug
和 cycript
調試界面是很是經常使用的手段 , 所以 , 但願你們能熟練掌握這些技巧 .