iOS逆向學習之八(動態調試)

什麼是動態調試?

動態調試就是在咱們的程序運行之時,經過下斷點、打印等一系列方式查看參數、返回值、函數調用流程等等。不只是在iOS開放中須要動態調試,在任何語言的開發過程當中都須要用到動態調試python

Xcode如何進行動態調試?

Xcode編譯器和調試器

  • Xcode最先使用的是GUN開發的GCC編譯器,可是從xcode5以後開始使用自研的LLVM編譯器,能夠點擊查看GCCLLVM的介紹
  • Xcode調試器早期也是使用的GUN開發的GDB調試器,以後也替換成了自研的LLDB調試器,能夠點擊查看GDBLLDB的介紹。

Xcode調試App的流程

  • 首先在Xcode中會自帶一個叫作==debugserver==的工具,存放在/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/De viceSupport/9.1/DeveloperDiskImage.dmg/usr/bin/debugserver目錄下,當咱們使用Xcode在iPhone上運行咱們的程序時,Xcode會將==debugserver==安裝到咱們的iPhone上,具體安裝路徑爲/Developer/usr/bin/debugserver
  • Xcode鏈接上手機後,經過自帶的==LLDB==編譯器向iPhone上的==debugserver==傳輸指令,==debugserver==接收到指令以後將指令運行到App中,App執行指令以後將結果返回爲==debugserver==,而後==debugserver==會將信息反饋給==LLDB==,最後==LLDB==會將信息打印到Xcode上。
  • 可是Xcode這種調試方式有很大侷限性,由於只能調試經過Xcod安裝的App

如何不經過Xcode動態調試任意App?

可使用終端取代Xcode來對App進行動態調試正則表達式

debugserver環境搭建

方法1、經過ldid進行簽名

  • 獲取到iPhone下/Developer/usr/bin/debugserver目錄中的debugserver工具,複製到Mac上
  • 因爲經過Xcode安裝的==debugserver==權限不足,只能調試Xocde安裝的App,因此咱們要給==debugserver==增長更多的權限。
  • 經過ldid -e指令導出==debugserver==的權限信息
ldid -e debugserver > debugserver.entitlements
複製代碼
  • 在debugserver.entitlements中增長如下兩個權限
    • get-task-allow
    • task_for_pid-allow

  • 經過ldid對==debugserver==進行從新簽名
ldid -Sdebugserver.entitlements debugserver
複製代碼
  • 因爲/Developer/usr/bin/目錄是隻讀的,因此咱們將從新簽名過的==debugserver==放在/usr/bin/下,而後對==debugserver==增長運行權限,就能夠在終端使用==debugserver==了
chmod +x /usr/bin/debugserver
複製代碼

方法2、經過codesign對debugserver進行簽名

#查看權限基本信息
codesign -d --entitlements - debugserver

#簽名權限
codesign -f -s - --entitlements debugserver.entitlements debugserver

#也能夠簡寫爲
codesign -fs - --entitlements debugserver.entitlements debugserver
複製代碼

讓debugserver附加到某個進程

debugserver *:端口號 -a 進程
複製代碼

*:端口號:表示使用iPhone上的某個端口啓動debugserver服務(注意:不能使用保留端口號)
-a 進程:指定進程id或者進程名稱express

使用debugserver啓動App

debugserver -x auto *:端口號 App可執行文件路徑
複製代碼

在Mac上啓動LLDB,遠程鏈接iPhone上的debugserver

在以前的學習中,咱們知道可使用iPhone的ip地址來鏈接手機,可是這樣須要保證手機和電腦在同一個wifi下,而且使用這種方式傳輸數據十分緩慢。因此,一般的作法是經過usb鏈接iPhone,將iPhone上的某個端口映射到Mac上的某個端口,而後然LLDB和Mac上的端口通訊便可xcode

debugserver attaching

  • 經過如下指令對iPhone的10089進行映射
python ./usbmuxd/tcprelay.py -t 22:10088 9999:10089
複製代碼

此處的10089端口能夠任意定義,只要不使用保留端口號便可。使用10088端口映射22端口,是爲了和iPhone進行SSH通訊bash

  • 映射成功以後,使用9999端口啓動==debugserver==服務。讓==debugserver==附加到騰訊視頻App進程,以下:
debugserver *:9999 -a live4iphone
複製代碼
  • 若是出現如下效果,代表==debugserver==已經成功attach到了騰訊視頻App上

在Mac上啓動LLDB,遠程鏈接iPhone上的debugserver服務

  • 首先在Mac上啓動LLDB
➜  ~ lldb
(lldb)
複製代碼
  • 經過Mac的10089端口鏈接==debugserver==服務
process connect connect://localhost:10089
複製代碼

  • 因爲鏈接上==debugserver==服務以後,程序是默認在斷點狀態,使用LLDB的c命令讓程序繼續運行
(lldb) c
Process 635 resuming
複製代碼

經常使用的LLDB指令

LLDB指令的基本格式

<command> [<subcommand> [<subcommand>...]] <action> [-options [option- value]] [argument [argument...]]
複製代碼

對應着app

命令 子命令 命令操做 命令選項 命令參數
複製代碼

例如給test這個函數設置斷點:iphone

breakpoint set -n test
複製代碼

help指令

help指令能夠幫助咱們快速查找LLDB指令的使用方法tcp

help breakpoint
help breakpoint set
複製代碼

expression -- 指令

expression指令被用來執行一個表達式函數

expression self.view.backgroundColor = [UIColor redColor]
//或者
expression -- self.view.backgroundColor = [UIColor redColor]
複製代碼
  • expression、expression --和指令print、p、call效果等同

  • expression -O -- 和指令po效果等同

expression後的 -- 表示命令選項結束符,表示全部的命令選項已經設置完畢,若是沒有命令選項,--能夠省略。若是expression以後有命令選項,則--不能省略。工具

thread backtrace

==thread backtrace==指令的做用是打印線程的堆棧信息,效果和 ==bt== 的效果相同。

(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000102d4d61d TestFont`-[ViewController touchesBegan:withEvent:](self=0x00007fd2f86066d0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000036d4ab0) at ViewController.m:26
    frame #1: 0x0000000106f6f8e8 UIKitCore`forwardTouchMethod + 353
    ......
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000102d4d61d TestFont`-[ViewController touchesBegan:withEvent:](self=0x00007fd2f86066d0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000036d4ab0) at ViewController.m:26
    frame #1: 0x0000000106f6f8e8 UIKitCore`forwardTouchMethod + 353
    ......
複製代碼

thread return []

讓函數返回某個值,不會執行以後的代碼。若是函數有返回值,在後面跟上返回值,若是函數沒有返回值,就直接使用thread return便可

frame variable []

打印當前棧幀的變量

thread相關指令

如下指令從左到右依次表示:指令全稱、指令簡稱、極簡指令

  • thread continue、continue、c :讓程序跳過斷點繼續運行
  • thread step-over、next、n :單步運行,將子函數當作總體一步執行
  • thread step-in、step、s :單步運行,遇到子函數會進入子函數
  • thread step-out、finish :直接執行完當前函數的全部代碼,返回上一個函數
  • thread step-inst-over、nexti、ni
  • thread step-inst、stepi、si

si、ni和s、n指令相似,可是s、n是源碼級別,si、ni是彙編指令級別。每一句OC代碼會有一條或多條彙編指令構成,s、n指令表示一步一步執行每一句OC代碼,而si、ni表示一步一步執行彙編指令。

breakpoint相關指令

breakpoint set

設置斷點

  • breakpoint set -a 函數地址
  • breakpoint set -n 函數名
    • breakpoint set -n test
    • breakpoint set -n touchesBegan:withEvent:
    • breakpoint set -n "-[ViewController touchesBegan:withEvent:]"
  • breakpoint set -r 正則表達式

此處跟上正則表達式,會將全部匹配到的方法都加上斷點

  • breakpoint set -s 動態庫 -n 函數名
    將指定動態庫的指定函數打上斷點

breakpoint list

列出全部的斷點,每一個斷點都有單獨的編號

breakpoint disable 斷點編號

禁用斷點

breakpoint enable 斷點編號

啓用斷點

breakpoint delete 斷點編號

刪除斷點

breakpoint command add 斷點編號

給指定斷點編號的斷點預先設置須要執行的命令,到觸發斷點時,就會按順序執行預先設置的命令

breakpoint command list 斷點編號

查看某個編號的斷點全部預先設置的命令

breakpoint command delete 斷點編號

刪除指定編號斷點的全部預設命令

內存斷點watchpoint

給指定的內存下斷點,當內存中的數據發生改變時會觸發

watchpoint set variable 變量

對指定的變量設置內存斷點,當變量值改變的時候會觸發

watchpoint set variable self->_age
複製代碼

注意:此處不能使用self.age

watchpoint set expression 內存地址

對指定內存地址設置斷點,做用和watchpoint set variable相同

watchpoint list

列出全部的內存斷點

watchpoint disable 斷點編號

禁用內存斷點

watchpoint enable 斷點編號

啓用內存斷點

watchpoint delete 斷點編號

刪除內存斷點

watchpoint command add 斷點編號

給指定斷點編號的內存斷點預先設置須要執行的命令,到觸發內存斷點時,就會按順序執行預先設置的命令

watchpoint command list 斷點編號

查看某個編號的內存斷點全部預先設置的命令

watchpoint command delete 斷點編號

刪除指定編號內存斷點的全部預設命令

image模塊查詢指令

image lookup

模塊查詢指令

  • image lookup -t 類型
    查找某個類型的信息

  • image lookup -a 內存地址
    根據內存地址查找在模塊中的位置

  • image lookup -n 符號或函數名
    查找某個符號或者函數的位置

image list

列出全部所加載的模塊信息

  • image list -o -f
    打印出模塊的偏移地址、全路徑

LLDB小技巧

  • 每次敲Enter鍵,都會自動執行上次的命令
  • 絕大部分的指令均可以使用縮寫
(lldb) breakpoint list
(lldb) br li
(lldb) br l

(lldb) breakpoint set -n test
(lldb) br s -n test
複製代碼
相關文章
相關標籤/搜索