iOS 逆向 - lldb高級篇 Chisel 與 Cycript

前言

上一篇文章 iOS 逆向 - LLDB 中講述了 lldb 的一些基礎用法 , 並無涉及太多其餘內容 , 逆向過程當中經常使用的動態調試方法其實還有一些 , 本文針對上篇文章和實際逆向中的運用進行一個補充 .git

主要針對 Chisel 以及 Cycript 兩個部分 .github

若是篇幅不長 , 咱們來說一講自定義 cy 指令.shell

逆向調試注意

  • 有部分同窗反應重簽名微信應用被封號的狀況 . 這裏說明一下 , 微信 / 抖音 等應用是有防禦和監測操做的 , 網上流傳部分破解微信防禦的 logos 代碼 , 筆者測試效果不是百分百 , 有須要的小夥伴能夠評論留言 .vim

  • 調試別人應用自己是會形成相似問題的 , 所以儘可能不要登陸我的使用帳號 , 如非必須登陸 , 不要登陸帳號 .ruby

  • 確實須要登陸 , 登陸一個小號 , 另外提早準備好另外一個帳戶去解封 .bash

  • 在越獄環境下 , 使用插件的方式調試 , 無須重簽名 , 被封號的概率是很低的 .微信

  • 最後再強調一次 : 玩逆向只是爲了更好地防禦 .app

Chisel

概述

Chisel 也是 Facebook 發佈的一個 lldb 的插件 , 可以作到幫助調試和提供用戶自定義指令集的功能 . 接下來會具體闡述 .函數

安裝

命令 : brew install chisel工具

( 尚未安裝 HomeBrew 的自行安裝 )

安裝後使用 : brew list 查看安裝結果

配置

如何配置 ?

1 -- 打開下載目錄

  • 先找到下載的文件 : cd /usr/local/Cellar/chisel
  • open . , 找到 fblldb.py 腳本文件.
  • cmd + opt + c 拷貝文件路徑.

2 -- lldb配置腳本路徑加載

  • 若是你的用戶家目錄下沒有 .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
  • 結果 :
  • 說明 : pviews 能夠幫助咱們很清楚的看出圖層邏輯層級關係以及內存地址 .
pvc 視圖層級
  • 指令 : pvc

  • 結果 :

  • 說明 : pvc 能夠幫助咱們很清楚的看出視圖控制器層級關係以及內存地址 .

pactions 事件查找

使用 pviews , 隨便找到一個按鈕 , 複製其內存地址 .

  • 指令 : pactions 0x10b06e5e0
  • 結果 :
  • 說明 : pactions 能夠拿到 buttontarget 以及 action , 在逆向時須要方法 hook 常常會使用.
presbonder 響應鏈

使用 pviews , 隨便找到一個按鈕 , 複製其內存地址 .

  • 指令 : presbonder 0x10b06e5e0
  • 結果 :
  • 說明 : presbonder 能夠查看完整的響應鏈.
pclass 繼承鏈

使用 pclass , 隨便找到一個類 , 複製其內存地址 .

  • 指令 : pclass 0x10b910600
  • 結果 :
  • 說明 : pclass 能夠查看完整的繼承鏈.
pmethods 查看類方法 / 實例方法
  • 指令 : pclass 0x106b57bc0
  • 結果 :
  • 說明 : pmethods 能夠查看類完整的類方法和實例方法.
pinternals 查當作員變量
  • 指令 : pinternals 0x10b660df0
  • 結果 :
fv / fvc
  • 指令 : fvc -v 0x10b8fe000
  • 結果 :
  • 說明 :
    • 經過內存地址查看類名 ( po 也能夠 ) . , 視圖控制器用 fvc , 視圖用 fv .
    • fv + 類名 反之是同樣的 , 回去工程搜索這個類 打印其內存地址 .
重點 : taplog
  • 指令 : taplog
  • 說明 : taplog 輸入後會退出斷點模式 , 再點擊屏幕上任何可響應視圖 , 會自動進入 lldb 模式並打印按鈕.
  • 結果 :
重點 : flicker
  • 指令 : flicker 0x11827c040
  • 說明 : 經過內存地址 , 在斷電模式下調用該指令會閃爍 view , 很是方便調試 , 以及肯定該內存地址是否爲咱們想找到的那個視圖 .
重點 : vs
  • 指令 : vs 0x11827c040
  • 說明 : 經過內存地址 , 進入調試模式 , 當前view會被添加紅色以便查看 .
  • 結果 :
(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>>
複製代碼
  • 退出 vs 調試模式 , q 指令 .
提示

最後三條指令在逆向過程當中很是經常使用 , 你們多加練習與掌握 .

lldb_commands 插件

這個 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 快速定位方法

找到視圖控制器地址 , 使用 methods 查看其全部的實例方法和屬性 .

注意 : 因爲逆向時 方法的符號是沒有恢復的 , 所以根據類名和方法名下斷點會失敗 .

函數調用棧

因爲符號並無恢復 , 所以 bt 指令查看函數調用棧時 , 會出現如下狀況 .

( 後續會講如何利用工具恢復 Mach-O 的符號 )

那麼此時 , 利用 lldb_commands 提供的 sbt 指令 , 會幫助恢復一些符號 , 以便於查看方法名稱 .

Mach-O Section 查看
  • 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

概述

Cycript 是由 Cydia ( 熟悉越獄的同窗應該都很清楚 ) 創始人 Saurik 推出的一款腳本語言,Cycript 混合了 OCJavaScript 語法的解釋器,這意味着咱們可以在一個命令中使用 OC 或者 JavaScript,甚至二者並用。

它可以掛鉤 正在運行的進程,可以在運行時修改不少東西。

到官網點擊 Download SDK 便可下載 .

安裝

  • 將下載後的文件夾放入 /opt/ 裏便可 , 也能夠自行選擇位置 .
  • 配置環境變量 .
  • 注意 : 這裏根據你使用的是 zsh 仍是 bash 去相應的資源文件配置 (家目錄下的 .zshrc / .bash_profile) .
  • 筆者因爲在 .zshrc 中也配置了 bash_profile 的引用 , 所以兩處來配置這個環境變量都是能夠的.

配置內容:

  • 添加 : export CY=/opt/cycript_0.9.594/ , 換成你本身的路徑.
  • export PATH= 中添加 :$CY

重啓 iTerm , 輸入 cycript , 便可查看 .

若是有遇到 ruby 環境不對的同窗 , 去下載對應版本的便可 . /System/Library/Frameworks/Ruby.framework/Versions

使用

在越獄環境下 , 是能夠在 Cydia 直接安裝 Cycript 插件的.

越獄手機截圖上傳有點麻煩 , 直接拍的.. 瑕疵請忽略 , 看個意思

那麼非越獄環境下 , 就要藉助 Cycript 提供的 iOS Framework , 注入進去了 . 並且在 MonkeyDev 中 , 是默認已經作好了 Cycript 的注入的 .

並且添加了 默認 6666 端口號的監聽 .

也就是說只要用 MonkeyDev 來重籤跑起來的程序進程 , 6666 端口就能夠附加使用了 ( 固然 , 在 Monkey 裏代碼能夠本身定義端口號 ) .

好了 說了這麼多 , 開始使用.

  • 1 . 保證電腦和手機在同一個局域網內 ( 由於要作端口映射 )
  • 2 . 運行 MonkeyDev 重簽名程序 / 或者直接打開之前重簽好的工程 , 無須 Xcode 運行也能夠
  • 3 . 終端輸入 cycript -r 192.168.0.116:6666
    • 換成你本身的手機 ip 地址
    • 另外 , 請不要將應用程序放到後臺 , 會影響附加.

出現如下 , Congratulations , you're good to go !

提示

使用 tab 鍵 , 寫代碼能夠補全 .

UIWindow.keyWindow()

查看當前 Window .

UIApplication sharedApplication

指令 : [UIApplication sharedApplication ] 可簡寫爲 UIApp

自定義變量

指令 : 本身 var 一個對象 , 然後咱們就可使用 .

另外注意 : 只要 APP 進程沒有掛 , 這個變量是一直存在的 .

# + 地址能夠直接使用

# + 對象地址 能夠直接調用對象的方法

查看視圖層級

UIWindow.keyWindow().recursiveDescription().toString()

隨便找一個 , 例如註冊頁面有一個 .text+86label , 拿到其內存地址 ,

命令 :

#0x10b95d800.text = "hhh"
複製代碼

顯示結果

基於這種直接修改進程內存的方式 , 你們能夠本身去玩一玩 . 好比登陸了修改一下錢包餘額 , 而後改一改 frame , 練習一下 .

如下指令結果我就不一一貼圖了 , 文章太長 , 不便閱讀 , 你們本身嘗試 .

獲取頁面上全部控件

choose(UIButton)

choose(UILabel)

隱藏 / 顯示狀態欄

[UIApp setStatusBarHidden:YES]

APP角標

[UIApp setApplicationIconBadgeNumber: 99]

獲取Bundle ID

APPID 結果 :

@"com.libin.LBMonkeyApp"

頁面層級

pviews()

pvcs()

根據按鈕地址獲取按鈕 target & Action

pactions (#0x10b29da40)

結果 :

"<WCAccountRegisterViewController: 0x10b9d9800> onAgreementCheckBoxClick:"
複製代碼

根據按鈕地址獲取響應鏈

rp(#0x10b29da40)

退出cy 調試模式

control + d

注意:

pviews / pvc / pactions / rp 這些指令是 MonkeyMDConfig.plist 中額外封裝了自定義的 cy 源的 . 也就是說使用越獄環境本來的 cycript 插件是沒有這些指令可用的 .

那麼咱們閒着也是閒着 , 咱們也來本身寫一個 cy 源來玩一下 ?

自定義 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 Debugcycript 調試界面是很是經常使用的手段 , 所以 , 但願你們能熟練掌握這些技巧 .

相關文章
相關標籤/搜索