了解一下xcode的調試app的原理:
我們xcode的調試原理是:首先mac電腦上會裝有lldb的這個調試器,他怎么來調試的呢,首先我們打上斷點會出現lldb調試階段,他首先會鏈接手機上上的debugserver,當然這個debugserver是在xcode的包文件里,當我們運行在手機上的時候他會將這個debugserver安裝到手機上,首先lldb會鏈接debugserver,這個debugserver在鏈接我們的
app,app將信息反饋給debugserver,debugserver在反饋給lldb。lldb在展示信息。
大致流程如圖:
其中debugserver在哪?
他的位置在這:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/De viceSupport/9.1/DeveloperDiskImage.dmg/usr/bin/debugserver
區分幾個關鍵詞:
xcode的編譯發展歷程:GCC -> LLVM
xcode的調試器的發展歷程:GNC -> LLDB
怎么動態調試app?
我們知道xcode是可以調試app的,但是他有一個局限性那就是他必須是有xcode運行起來才能打斷點進行調試。但是裝到自己手機的app是不能夠用xcode進行運行的,我們的解決辦法是:用終端的lldb,連接到我們的手機,然后進行調試。
- 給我們手機debugserver付給他更高的權限
我們在手機的/device/developer/usr/bin 目錄下找到debugserver,這個debugserver是xcode給我們安裝到的,如果你是新的手機 沒有用xcode調試過按道理來說是沒有這個的。那么你需要時xcode調試一次。將這個debugserver拿到桌面,查看他的權限。
執行這個命令:
ldid -e debugserver > debugserver.entitlements
如果你還沒有安裝ldid那么請用homebrew進行安裝ldid,另外注意一下我的路徑
執行完命令后在桌面上生成了:
我們用xcode將他打開,可以看到權限不多,現在我們要給他添加權限,并且重新付給debugserver權限。
我們要給他添加如下的權限:
get-task-allow 和task_for_pid-allow 都是bool類型
我的添加好了如下:
現在我們將這個權限從新賦值給debugserver
執行如下命令:
ldid -Sdebugserver.entitlements debugserver
為了確保我們的權限賦值成功了,需要驗證一下,我們重新生成debugserver的權限看下是不是賦值好了。
執行如下的命令:
ldid -e debugserver > abc.entitlements
可以看到我們的權限表為:
當然我們也可以用codesign進行簽名:
這說明我們配置好了,將這個debugserver拖拽到手機的 /usr/bin 目錄下,切記不是/device/developer/usr/bin 目錄,因為這個目錄是只讀的。
注意點:可能你拖拽的時候的你的ifunbox可能會閃退,我就出現了這個問題,怎么解決呢?那么就用終端命令吧
scp -P 10010 ~/Desktop/debugserver root@localhost:/usr/bin
如果你只是有一個越獄的手機那么執行這個命令可能是不正確的,因為我現在命令的意思是連接10010那個端口,你需要做的是配置手機鏈接,其實這個還是挺復雜的,你如果完全弄明白需要看我的越獄第一篇文章,越獄環境的搭建。我的執行完命令如下:
可以看到提示這個錯誤:No space left on device
通過ifunbox來查看如下:
而我們的debugserver實際上是有14M的,這說明不對,我猜測的原因有以下幾個:
1.我的手機不是完美越獄的
2.在usr/bin 不能放大文件
我嘗試著放到bin目錄下還有usr/sbin目錄下都是不行的,經過一番在網上查閱資料最后發現也有人遇到我的問題他放到root目錄下了,但是這樣的話會有一個問題就是不能再其他的目錄下出現提示,要想在任意的文件夾出現提示 需要配置手機的環境變量,這里我就不介紹了 我也沒有配置,但是你要想配置的話我之前的文章有介紹過配置mac的,手機的一樣的道理。
但是現在這個文件的權限是不夠的,比如:
注意我的路徑這次是在手機的路徑輸入的。
下面執行這個命令:
chmod +x debugserver
注意我的路徑位置:
下面我們將我們的端口作為映射,因為之前映射是22:10010,那個是我們之前連接ssh的時候,代碼為:
然后執行一下命令
./debugserver
現在我們需要在usb.sh中增加一個一個端口映射,那就是10011:10011,這個你用別的也行只是不要用系統占用的比如:8080 1024 什么的。
下面我改usb.sh為:
python ~/Desktop/Common/usbmuxd-1.0.8/tcprelay.py -t 22:10010 10011:10011
- 讓debugserver附加到某個app的進程
執行如下的命令:
debugserver *:端口號 -a 進程的id或者進程的名字
比如我將debugserver附件到微信上
./debugserver *:10011 -a WeChat
lldb進行鏈接debugserver 在微信中打斷點
經過上面的一套的配置,現在需要lldb進行鏈接debugserver了,首先在電腦的終端輸入lldb那么就進入了lldb環境了
比如我的是:
下面用lldb鏈接debugserver,執行這個命令
process connect connect://localhost:10011
注意:為什么是localhost因為我們剛才已經映射了端口了
這時候會出現如下的畫面:
這說明一個斷點打在可微信上了。
這時候會卡住不動,你只需要執行如下的命令:
c
continue 的意思 微信就可以繼續點擊了
比如我的是這樣的:
至此鏈接搭建完成了。
lldb的語法介紹
breakpoint的介紹
從字面上的意思是打斷點,比如我們在工程文件中寫一個函數,我不手動打斷點,直接調用命令來進行打斷點看下。
breakpoint set -n test
可以看到他自動進入了那個方法。
解釋:
breakpoint :斷點
set:設置
-n:name 名字的意思
test :函數名稱
- help的使用
當我們忘記一個命令的時候 可以借助help來幫助我們
比如我查breakpoint的:
help breakpoint
上圖顯示的是他的子命令,然后在繼續執行這個命令:
help breakpoint set
然后在輸入:
breakpoint set -n test
比如我們給一個函數打斷點還可以這樣使用
breakpoint set -n "-[ViewController touchesBegan:withEvent:]"
解釋比如:我們如果輸入:touchesBegan:withEvent: 那樣的會找到很多的方法,有可能系統的方法也找到了。如下圖:
- breakpoint set -r 正則表達式
比如我這樣輸入:
breakpoint set -r test1233
- breakpoint set -s 動態庫 -n 函數名字
比如我的
breakpoint set -s libate.dylib -n freePartitionTables2D
我就是給libate.dylib動態庫的這個freePartitionTables2D函數設置了一個斷點
-
breakpoint list 列出所有的斷點
比如我的是:
image.png -
啟用、禁用、刪除斷點
image.png
比如我的
breakpoint disable 2
發現點擊控制器斷點不停住。
其他兩個不在說明了。
- 給斷點預先設置需要執行的命令
breakpoint command add 斷點編號
- 查看某處的斷點命令
breakpoint command list 斷點的編號
- 刪除每個斷點設置的命令
breakpoint command delete 斷點的編號
內存斷點
大致如下,不在舉例子
image lookup的使用
- 查找某個類型的信息
image lookup -t 類型
- 根據內存地址查找某個模塊的位置
image lookup -a 內存的地址
- 查找某個符號或者函數的名字
image lookup - n 符號或者函數的名字
image list 的使用
- 打印模塊的全路徑和偏移地址
image list -o -f
- expression 的使用
他的主要作用是比如:有時候在打斷點的時候,我們這個斷點過了 但是我們又不想從新在執行在執行程序,那這個時候就需要這個了
比如我在當前的斷點處執行:
expression self.view.backgroundColor = [UIColor redColor]
點擊單步走 可以看到結果為:
簡單介紹:
- thread 的使用
打印堆棧信息
thread backtrace 或者也可以為:bt
讓函數直接返回某個值,不會執行斷點后面的代碼
thread return []
比如我的:
thread return 0
點擊下一步直接退出后面的所有的斷點,也沒有打印了。
查看當前的棧幀變量
frame variable
下面是我們最常用的幾個:
下面是我的執行結果
c
可以看到他是從第一個斷點跳轉到第二個斷點。
s
可以看到他是單步走,遇到函數直接進去,其實他對應xcode這個地方
n
可以看到他遇到函數直接當一句話直接過
finish
可以看到在當前函數執行finish直接退出當前函數
si s 、n ni的區別:
其中si ni 是指令級別的。
而n、s是源碼界別的
也就說si ni 是一般來說我們來看匯編指令的時候運用的,比如我首先設置xcode如下
然后我們直接就看nslog的輸入,首先我輸入:
s
可以看到直接從20跳到24行,現在我開始運行si
si
可以看到他是直接一步一步的執行。n和ni同理。
ALSR的簡單說明
我們通過hopper或者machoview 查看的是虛擬內存,也就是不是真實函數的內存,以前沒有ALSR的情況下,如果黑客知道你起始的內存地址,那么他就可以知道一連串的其他的地址,這樣的話就會存在危險。如果我們通過一定的手段來創建一個偏移地址,這個偏移地址加上我們現在看到的起始地址才是真正的函數的地址那么就能確保安全的這個問題?,F在ALSR個人認為就是:隨機的偏移地址。
- 至此動態調試應該會了。