參考部落格:
https://juejin.cn/post/6872764160640450574#heading-4 (斷點後續指令)
https://www.jianshu.com/p/67f08a4d8cf2 (斷點相關)
基礎環境搭建
在x-code目錄中找到對於版本的DeveloperDiskImage.dmg ,路徑大致/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/9.2/DeveloperDiskImage.dmg
雙擊DeveloperDiskImage.dmg
在/Volumes/DeveloperDiskImage/usr/bin/ 下找到debugserver.
debugserver複製出來
建立一個entitlement.xml檔案與debugserver保持同一目錄
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.springboard.debugapplications</key>
<true/>
<key>get-task-allow</key>
<true/>
<key>task_for_pid-allow</key>
<true/>
<key>run-unsigned-code</key>
<true/>
</dict>
</plist>
用codesign對debugserver簽名, 命令如下:
codesign -s - --entitlements entitlement.xml -f debugserver
scp -r debugserver root@192.168.2.17:/usr/bin/ #192.168.2.17 是 iPhone 裝置的 ip 地址.
debugserver 拷貝到iOS中 目錄為/usr/bin/
pc終端命令列視窗1、2中,建立埠代理
iproxy 1998 1998
iproxy 2222 22
pc終端命令列視窗3中連線手機的ssh
#這裡前提要安裝OpenSSH,Cycript
ssh root@localhost -p 2222
#預設密碼是alpine
手機終端中輸入
ps -e |grep app
#找到對應的app
#如/var/containers/Bundle/Application/4CF47160-4687-41C9-B987-EB40B541A461/pinduoduo.app/pinduoduo
手機端開啟debugserver
debugserver -x backboard 127.0.0.1:1998 /var/containers/Bundle/Application/4CF47160-4687-41C9-B987-EB40B541A461/pinduoduo.app/pinduoduo
pc終端命令列
執行
lldb
process connect connect://127.0.0.1:1998
#如果此事介面出現報錯或者停止 按C繼續執行,可以先下好斷點再執行
image list -o -f # 第一行即為獲取 獲取ASLR偏移地址
#[ 0] 0x00000000007a0000 /private/var/containers/Bundle/Application/4CF47160-4687-41C9-B987-EB40B541A461/pinduoduo.app/pinduoduo(0x00000001007a0000)
00000000007a0000 為ASLR偏移地址
計算ptrace偏移後地址
p/x 0x0000000101319A8C + 0x00000000007a0000 # [ptrace偏移後地址] = 方法位置+ ASLR偏移地址
br s -a [ptrace偏移後地址]
設定斷點相關 (每一行代表一種寫法)
給所有名為xx的函式設定一個斷點
(lldb)breakpoint set —name xx
(lldb)br s -n xx
(lldb)b xx
在檔案F指定行L設定斷點
(lldb)breakpoint set —file F —line L
(lldb)br s -f F -l L
(lldb)b F:L
給所有名為xx的C++函式設定一個斷點(希望沒有同名的C函式)
(lldb)breakpoint set —method xx
(lldb)br s -M xx
給一個OC函式[objc msgSend:]設定一個斷點
(lldb)breakpoint set —name “[objc msgSend:]”
(lldb)b -n “[objc msgSend:]”
給所有名為xx的OC方法設定一個斷點(希望沒有名為xx的C或者C++函式)
(lldb)breakpoint set —selector xx
(lldb)br s -S count
給所有函式名正則匹配成功的函式設定一個斷點
(lldb)breakpoint set --func-regex regular-expression
(lldb)br s -r regular-expression
給指定函式地址func_addr的位置設定一個斷點
(lldb)br set -a func_addr
斷點檢視
(lldb)breakpoint list
(lldb)br l
斷點刪除
(lldb)breakpoint delete index
(lldb)br del index
index指明斷點的序號,如果為空則刪除所有斷點
斷點後續移動操作
原始碼級別(和你ida彙編看到一樣的一步一步)
step-in步入會
進入函式內部
(lldb) thread step-in
(lldb) step
(lldb) s
step-over步入不會
進入函式內部
(lldb) thread step-over
(lldb) next
(lldb) n
指令級別
step-in 在彙編介面,跳轉下一步,在有bl指令的地方,si會
單步進入到bl指令所跳轉的子函式內部
(lldb) thread step-inst
(lldb) si
step-over 在彙編介面,跳轉下一步,在有bl指令的地方,ni不會
單步進入到bl指令所跳轉的子函式內部
(lldb) thread step-inst-over
(lldb) ni
step-out 從一個函式跳出
(lldb) thread step-out
(lldb) finish
(lldb) f
下一個斷點
c
lldb常用命令(以下需要斷點命中後操作)
1.計算表示式命令(expression、po、p)
expression可簡寫為expr
計算以及生成一個表示式
(lldb) expr (int)printf ("Print nine: %d.\n", 4 + 5)
Print nine: 9.
(int) $0 = 15
建立一個變數並分配值
(lldb) expr int $val = 10
(lldb) expr $val
(int) $val = 10
exp列印值、修改值
(lldb) expr width
(CGFloat) $0 = 10
(lldb) expr width = 2
(CGFloat) $1 = 2
(lldb) po width
2
(lldb) p width
(CGFloat) $3 = 2
p、po與expr的關係
(lldb) expr -- person
(Person *) $0 = 0x000000010053b7f0
(lldb) p person
(Person *) $1 = 0x000000010053b7f0
(lldb) expr -o -- person
<Person: 0x10053b7f0>
(lldb) po person
<Person: 0x10053b7f0>
總結
p是expr --的簡寫,它的工作是把接收到引數在當前環境中進行編譯,然後列印出來
po是expr -o --的簡寫,它所做的操作和p相同。如果接收到的引數是一個指標,那麼它會呼叫物件的description方法並列印;如果接收到的引數是一個core foundation物件,那麼它會呼叫CFShow方法並列印。如果這兩個方法都呼叫失敗,那麼po列印出和p相同的內容。
使用p做進位制轉換
//預設列印為10進位制
(lldb) p 10
(int) $0 = 10
//轉16進位制
(lldb) p/x 10
(int) $1 = 0x0000000a
//轉8進位制
(lldb) p/o 10
(int) $2 = 012
//轉二進位制
(lldb) p/t 10
(int) $3 = 0b00000000000000000000000000001010
//字元轉10進位制數字
(lldb) p/d 'A'
(char) $4 = 65
//10進位制數字轉字元
(lldb) p/c 66
(int) $5 = B\0\0\0
記憶體讀取
(lldb) x person
0x10053a6b0: 5d 22 00 00 01 80 1d 00 00 00 00 00 00 00 00 00 ]"..............
0x10053a6c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
(lldb) x/4gx person
0x10053a6b0: 0x001d80010000225d 0x0000000000000000
0x10053a6c0: 0x0000000000000000 0x0000000000000000
(lldb) x/3wx person
0x10053a6b0: 0x0000225d 0x001d8001 0x00000000
(lldb) x &width
0x7ffeefbff4f0: 00 00 00 00 00 00 00 00 b0 a6 53 00 01 00 00 00 ..........S.....
0x7ffeefbff500: 30 f5 bf ef fe 7f 00 00 01 00 00 00 00 00 00 00 0...............
(lldb) x/4gx &width
0x7ffeefbff4f0: 0x0000000000000000 0x000000010053a6b0
0x7ffeefbff500: 0x00007ffeefbff530 0x0000000000000001
(lldb) x/4go
0x7ffeefbff510: 03777735757772440
0x7ffeefbff518: 03777755321776311
0x7ffeefbff520: 00
0x7ffeefbff528: 01
x是讀取記憶體的命令,x/4gx中第一個x是讀取記憶體命令,後面的g是每次讀取8位元組,x的意思是16進位制顯示結果,4表示連續列印4段。
對於g,常用的大小格式為b對應byte 1位元組,h對應half word 2位元組,w對應word 4位元組,g對應giant word 8位元組
對於x,我們還可以用o對應8機制,b對應2進位制,x對應16進位制,f對應浮點,d對應10進位制
call方法呼叫
(lldb) call width
(CGFloat) $0 = 0
(lldb) call testFunction()
123456
複製程式碼
4.變數檢查(frame)
(lldb) fr v b
(Int??) b = nil
(lldb) fr v -r b
(Int??) b = nil
(lldb) fr v -R b
(Swift.Optional<Swift.Optional<Swift.Int>>) b = some {
some = none {
some = {
_value = 0
}
}
}
(lldb) fr v -a b
(Int??) b = nil
我們常用fr v -R來檢視型別的結構