當前位置:
首頁 > 最新 > 鎖定APP的目標類與函數

鎖定APP的目標類與函數

上一節小程介紹了怎麼獲取APP的所有類的結構信息,以這一步為基礎,下一步可以通過注入來做更多研究工作。

注入的最小單位是函數,實際上,編譯執行的程序在編譯後,類就不復存在了,留給小程的只是二進位代碼(指令或數據都是一樣的二進位代碼)。所幸的是,跟小程打交道的,並不是二進位代碼(那會困難很多),而是函數,而且是某個類的函數。

那麼,在用classdump拿到成千上萬個類與函數後,哪個函數才是小程關心的呢?怎麼鎖定它們呢?

本文介紹鎖定目標類與函數的可行的辦法。

基本上小程研究的目標APP都是有豐富的界面的,而小程關心的場景基本都是由特定的界面觸發,所以,從界面入手是個不錯的選擇。

有沒有辦法找出某個界面對應哪一個類呢?然後就可以在classdump拿到的眾多的類中仔細研究這個界面類擁有的函數與成員變數。

小程覺得目前最好的辦法就是使用Reveal工具。

(一)使用Reveal

先下載一個Reveal(有破解版本),比如1.6版本或1.5版本。

(1)拷貝libReveal.dylib到手機

Reveal最大的一個作用是把手機上的某個APP的界面同步顯示到電腦上,要做到這個效果,Reveal既要在電腦上運行,同時也要把一個「內鬼」打入到手機。這個打入手機的「內鬼」就是libReveal.dylib。

在電腦上運行Reveal後,點擊菜單Help,選擇Show Reveal Library in Finder,再點擊iOS Library,就可以找到libReveal.dylib。

拷貝到DynamicLibrary目錄下:

基本上,手機上的APP在啟動運行後,都可以載入DynamicLibraries裡面的動態庫(以dylib為後綴),至於載入哪個動態庫,則由plist文件決定。這個知識點很重要,這意味著你可以寫一個plist文件,讓某個APP在啟動時載入你寫的動態庫,這是注入的前提。

/Library/MobileSubstrate/DynamicLibraries,在手機成功越獄後就會存在。

(2)拷貝libReveal.plist到手機

找一個plist文件來修改,或者直接寫一個plist文件,命名為libReveal.plist。

libReveal.plist文件要指定讓哪個APP啟動時載入Reveal.dylib,比如:

Filter

Bundles

com.tencent.QQKSong

上面的plist內容,讓「全民k歌」啟動時,載入Reveal.dylib。

com.tencent.QQKSong,是「全民k歌」的BoudleID。至於目標APP的BoundleID是多少,有很多辦法可以查到,比如找到它的plist文件來查看,比如ps看進程信息,比如動態調試等等。

小白:如果不指定這個Filter呢,是不是所有的APP啟動時都載入?

小程:iOS8之前的版本是這樣的,但之後的版本都需要指定APP。所以,不管3724,加上這個Filter總是不會錯的。

之後,在電腦上再次啟動Reveal就可以連接目標APP,來分析界面類了。

比如,在手機上重啟全民k歌,在電腦上重啟Reveal並選擇菜單項,連接全民k歌:

可以看到,全民k歌的一個頁面是這樣(右下角的類名是重點):

(二)讓全民k歌自動切換至歌手頁面

為了「感性」一點,小程做一個演示,通過Reveal定位到全民k歌的目標類,並讓全民k歌啟動後自動切換至歌手頁面。

首先通過Reveal,定位到底部導航條的所在的viewcontroller類:

也就是KSRootTabBarController

然後,通過查看classdump翻譯到的類結構中,找到這個類。可以看到,點擊「我要唱」按鈕,實際就是觸發KSRootTabBarController::onClickTabBarItem函數。

接著,就可以hook這個類了,讓目標APP自動跳轉。這一步的具體操作,小程會在後續詳細介紹,讀者只需要「感性」地知道這回事就好。

最終,自動跳轉的效果是這樣的:

GIF

以上小程講解了Reveal的使用。Reveal是定位目標類與函數的有效的辦法,除了這個辦法,還有一個辦法就是,觀察所有類的類名,猜測可能有關係的類(比如應該具備某個關鍵字),再注入這些類的函數並用NSLog輸出信息,或者動態調試觀察執行的流程,最終確定目標類與函數。

小程在這裡介紹動態調試目標APP的辦法,這個辦法在「漫天定位」的時候可能有用,實際大多數情況下可能不必用到。讀者可以在需要時再閱讀這部分內容。

目標:在電腦上遠程調試手機上的進程。

(一)問題(1)為什麼不用本地調試的方式?

可以在手機上安裝gdb,再使用gdb調試目標進程。但因為本地用gdb來調試可能會遇到很多gdb本身的問題(有一些可以解決,而有一些並不好解決),而lldb被蘋果支持,並用於替代gdb。所以,可考慮使用更好的工具,即lldb+debugserver來遠程調試目標進程。

(2)需要什麼工具?

電腦上需要lldb,如果mac電腦上安裝了xcode那就會有lldb。

手機上需要安裝debugserver。

(3)手機如何安裝debugserver?

debugserver在哪裡?

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/xx.xx(目標手機是什麼系統就選擇什麼版本的目錄),雙擊下面的文件:DeveloperDiskImage.dmg,在打開的finder中,usr/bin目錄中存放了debugserver。

怎麼定製手機上相應的debugserver?

(a)

雙擊打開DeveloperDiskImage.dmg後,

cd /Volumes/DeveloperDiskImage/Library/PrivateFrameworks,

scp -r ARMDisassembler.framework root@192.168.2.22:/System/Library/PrivateFrameworks/,

即把ARMDisassembler.framework拷貝到手機,之所以這樣做,是據別人的經驗,可以讓lldb看彙編代碼的效果更好,不妨照做。

(b)

把usr/bin中的debugserver拷貝到另一個目錄,為後續的簽名作準備。

(c)

創建一個entitlement.xml文件,內容如下:

com.apple.springboard.debugapplications

get-task-allow

task_for_pid-allow

run-unsigned-code

(d)

使用ldid來簽名:

ldid -Sentitlement.xml debugserver

在手機上測試是否可用(比如ssh到手機後輸入命令):

debugserver

(4)重簽名工具ldid怎麼安裝?

如果有安裝iOSOpenDev,那在目錄/opt/iOSOpenDev/bin/下面就有ldid。

如果沒有,那可以拉代碼下來安裝:

git clone git://git.saurik.com/ldid.git

cd ldid

git submodule update --init

./make.sh

which ldid #查看是否安裝成功

(5)怎麼使用debugserver與lldb?

在手機上啟動伺服器debugserver:

debugserver *:54321 -a "Spotify"

*表示偵聽任意ip的連接,54321為埠,-a連接目標進程的名稱(可用ps取得)。

然後,在電腦上啟動lldb並連接伺服器:

process connect connect://192.168.2.22:54321

如果手機端的debugserver提示:Waiting for debugger instructions for process 0,那說明已經連接上。

之後可以在lldb端發送命令,比如查看當前調試進程的模塊信息:

image list -o -f

注意,第一次image list -o -f,可能要等上幾分鐘。當有返回後,再輸入c,就可以讓程序繼續運行。

(6)如果覺得debugserver運行很慢,怎麼解決?

使用usbmuxd來啟用數據線來調試。

* 如何安裝與使用usbmuxd?

* 下載:http://7xibfi.com1.z0.glb.clouddn.com/uploads/default/original/2X/a/aa9cecf05b47d08a59324edeaaeea3f17e0608ee.zip

* 具體使用可以參考:http://www.jianshu.com/p/9333a706641a。

小程直接用lldb跟debugserver,第一次image list等了幾分鐘,整體還可以接受

(7)怎麼調試?

* debugserver *:54321 -a "Spotify" --手機上啟動debugserver並附加到目標進程

* lldb --電腦上啟動lldb

* process connect connect://192.168.2.22:54321 --lldb連接debugserver

* image list -o -f --查看目標進程的所有模塊的信息,比如輸出:

[ 0] 0x000d8000 /var/containers/Bundle/Application/A80AF35B-DAD3-4D7E-B467-6C4230E32556/Spotify.app/Spotify(0x00000000000dc000)

第二個值為程序在內存中的基地址,記錄這個值。

* br s -a (0x000d8000+目標代碼的偏移地址)

* c --讓程序繼續執行

* (操作程序)讓程序觸發斷點。

* 使用lldb命令進行調試。

(二)示例

這裡簡單演示下怎麼調試Spotify這個APP。

從class-dump得到的信息,嘗試調試類SPTNowPlayingBarModel的pause函數,看看在播放bar條上暫停播放時會不會斷在這個函數上。

class-dump得到的pause的地址是0x00477ff1,在hopper上跳轉到這個地址(G),也可以看到-[SPTNowPlayingBarModel pause]的信息。

* 運行目標應用

* debugserver *:54321 -a "Spotify" 手機端啟動伺服器,之後都在客戶端lldb中操作。

* lldb

* process connect connect://192.168.2.22:54321

* image list -o -f 或 image list -o -f grep Spotify

這一步可能要等一會,在ipod5的6.0系統會很快,而在iphone5s的10.1.1系統則很慢。

* 從上面的命令找到基地址為:0x000e6000 (每次運行不一樣)

* 查看一下即將下斷點的代碼是怎麼樣的:dis -a "0x000e6000+0x00477ff1" 結果跟用hopper看到的一樣(0x0047ff1處)。

* br s -a "0x000e6000+0x00477ff1"

* c

* 讓程序觸發到斷點,使用lldb的命令查看數據或設置值,或單步等。

(三)lldb的常用命令

列印信息:

expr或e、po、p或print

display 表達式

undisplay 序號

斷點:

br l或breakpoint list#所有斷點

breakpoint set -a 函數地址,可簡寫:br s -a xxx #下斷點

br s --函數關鍵字(可模糊)

breakpoint set --shlib foo.dylib --name foo

br del 1#刪除斷點

br del 2 3 4#刪除幾個斷點

內存斷點

watchpoint set expression 地址

watchpoint set variable 變數名稱

條件斷點

watchpoint modify -c 表達式

單步:

s/si#單步進入函數

n/ni#單步

f#跳出函數

線程:

thread backtrace,或bt,或bt all #列出所有線程

模塊信息:

image list [-o -f]

image lookup -a expression

image lookup -a $pc

image lookup -r -n xxx

image lookup -r -n playPause #用來查看一個函數(關鍵字)的地址

image lookup -r -s

顯示地址處的代碼:

disassemble/dis -a 地址

dis -a $pc

dis -s 0x0002c000 -c 9 #後面的參數-c用來限制顯示的代碼數。

內存操作:

memory read [起始地址 結束地址]/寄存器 -outfile 輸出路徑

寄存器操作:

register read/格式

register write 寄存器名稱 數值

總結一下,本文重點在於使用Reveal,從界面入手,定位到關鍵類與函數,進而找到目標類與函數,為分析借鑒或注入提供基礎。對於動態調試,讀者未必需要掌握,如果它實際幫不到你的話。使用Reveal的難度係數為低,而動態調試的難度為中。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 全球大搜羅 的精彩文章:

小心那些主動給你發紅包的人

TAG:全球大搜羅 |