iOS逆向與安全:基礎篇
從本篇文章開始,筆者會整理iOS逆向相關的筆記。作為一位新人,希望通過整理筆記能夠更好的理解和掌握知識。能力有限,在行文時難免出現錯誤歡迎批評和指正。
前期準備:
如何越獄
網上有很多教程幫助你來越獄,這裡推薦兩個網站:
注意:在購買iOS裝置時直接購買對應版本的系統,由於蘋果官方關閉降級通道所以無法刷韌體降級。
越獄成功後,桌面上會出現一個叫做 Cydia
的應用,它是越獄後的 App Store
可以安裝各種第三方的軟體,比如:外掛、補丁、APP等。該應用的作者 Jay Freeman(saurik)
,一位骨灰級大神。
必裝外掛或補丁
-
Apple File Conduit 2
:可以訪問整個iOS裝置的檔案系統。作者是Jay Freeman
。 -
AppSync unified
: 可以繞過系統驗證,隨意安裝、執行破解的IPA安裝包。 -
PP助手
: 一個應用商店,可以自由安裝海量APP。 -
OpenSSH
: 用於遠端登入iOS裝置。
Mac 必備
iFunBox PP助手 iTerm2 Alfred
配置遠端登入
SSH:Secure Shell的縮寫,安全外殼協議,是一種可以為遠端登入提供安全保障的協議。使用SSH可以把所有傳輸的資料進行加密,防止中間人攻擊、DNS欺騙和IP欺騙。
OpenSSH: 是SSH協議的免費開源實現。通過它讓Mac登入iOS裝置,在 Cycript
中搜索安裝。
使用密碼登入
如果iOS裝置上已經安裝了 OpenSSH
,此時就可以通過Mac終端登入iOS裝置。前提,iOS裝置和Mac需要處於相同WiFi環境下。在設定中檢視iOS裝置的IP地址。開啟終端輸入:
ssh root@iOS裝置IP地址 // 回車,會提示時候建立連線輸入yes即可。之後提示輸入密碼,預設密碼是`alpine`。
iOS裝置上有兩個預設賬號:root,mobile。
- root:最高許可權賬戶,$HOME是
/var/root
。或者通過終端輸入pwd
檢視。 - mobile:普通許可權賬戶,只能操作一些普通檔案,$HOME是
/var/mobile
。 -
mobile
登入方式:ssh mobile@伺服器地址
。初始密碼alpine
。 - 修改root密碼:
passwd
,修改mobile
使用者密碼:passwd mobile
。
公鑰登入
上面的密碼登入方式比較麻煩,在每次登入時都需要輸入密碼。SSH提供了公鑰登入,以省去密碼的步驟。下面來看看公鑰登入流程:
將電腦端的SSH公鑰儲存在iOS裝置中,登入時iOS裝置端會向電腦端傳送一個隨機字串,登入使用者通過自己的私鑰加密後傳送給iOS端,iOS端通過事先儲存好的公鑰解密,如果解密成功,證明使用者是可信的。
檢視 $HOME/.ssh/
目錄,是否有 id_rsa
私鑰和 id_rsa.pub
公鑰,如果沒有使用 ssh-keygen
生成。
上傳公鑰到遠端裝置,通過 ssh-copy-id
命令。
ssh-copy-id -i $HOME/.ssh/id_rsa.pub root@地址
該條命令的作用是將 id_rsa.pub
公鑰追加到iOS裝置的 $HOME/.ssh/authorized_keys
檔案中。
cat $HOME/.ssh/authorized_keys //檢視檔案內容
通過USB登入裝置
在WiFi不穩定的情況下,通過WiFi登入會非常的卡頓。可以通過介面轉發的方法,使用USB SSH登入,保證連線的穩定性。
方法很簡單,首先安裝 libimobiledevice
,然後使用裡面提供 iproxy
把本地埠(例如:2222)對映到裝置的TCP埠22,就可以通過本地的2222埠建立連線了。
brew install libimobiledevice iproxy 2222 22 ssh root@localhost -p 2222
如果,每次輸入 iproxy 2222 22
進行介面轉換比較麻煩,可以將其配置到電腦的開機啟動項中。建立 ~/Library/LaunchAgents/com.usbmux.iproxy.plist
,填入一下:
執行命令 launchctl load ~/Library/LaunchAgents/com.usbmux.iproxy.plist
使之生效。
每次輸入 ssh root@localhost -p 2222
也很麻煩,可以通過指定一個名稱進行SSH連線,開啟 $HOME/.ssh/config
檔案,沒有建立一個,寫入一下內容。
Host ipad Hostname localhost User root Port 2222
通過以上配置,在終端輸入 ssh ipad
即可登入iOS裝置了。
砸殼
在 App Store
下載應用都會進行加密,破解加密稱為砸殼。本節記錄在學習砸殼中遇到的問題和解決方法。
三種砸殼方案:
這三種方案網上很多教程,下面整理的是第三種方案簡單高效。
配置環境
iOS裝置和電腦都需安裝 Frida
,
iOS裝置安裝 Frida
,開啟 Cydia
新增軟體源 https://build.frida.re
,之後搜尋 Frida
安裝。電腦端通過 pip
命令 sudo pip install frida
安裝。
接下來,克隆 frida-ios-dump 庫到本地。倉庫有兩個分支分別對應 python2.x
和 python3.x
,需要根據本地 Python
版本來判斷。
// Mac終端 python -V // 筆者:Python 3.6.3 :: Anaconda custom (64-bit)
由於筆者配置的 Python 3.x
,切換到3.x分支安裝 firda-ios-dump
依賴。在 frida-ios-dump
倉庫目錄下執行下面命令。
sudo pip install -r requirements.txt --upgrade
安裝結束後,將越獄裝置通過USB連上電腦進行埠對映:
iproxy 2222 22
到此配置結束,如果一切順利就可以進行砸殼了。
進行砸殼
在 frida-ios-dump
目錄下,使用命令 ./dump.py -l
檢視應用名稱和 Bundle ID
,通過命令 ./dump.py + 程式名字 or BundleID
即可砸殼。當程式執行完,在當前目錄中會出現一個 xxx.ipa
。
不過,通往成功的道路永遠不是一帆風順的,在執行 ./dump.py
命令是出現了錯誤 Waiting for USB device… 。在這個 issue
中給出瞭解決方案。
推薦文章 一條命令完成砸殼
Reveal配置
Reveal是一款用於檢視程式介面結構和除錯介面的工具,可以在開發中動態修改除錯程式碼修改程式的樣式,也可以注入到第三方APP檢視應用的介面結構。
本節將會學習如何在越獄裝置和非越獄裝置上檢視應用的結構。
越獄裝置整合Reveal
筆者在越獄裝置整合Reveal遇到了一個問題,新版的 RevealServer
是 Framework
而舊版的是 dylib
,兩者整合方式不同,但是網上很多資料都是過時的,所以這裡給出新版的整合方式。
首先在 Cydia
下載 Reveal2Loader
外掛。外掛安裝後進入設定找到 Reveal-->Enabled Applications
選擇要檢視的App。例如:簡書
電腦端安裝 Reveal
軟體,正常情況下,開啟手機上的簡書APP會在 Reveal
中看到下圖,點選進入即可檢視介面結構。

有時會出現 RevealServer.framework
版本問題,電腦端點選 Help->Show Reveal Library in Finder
將 Framework
拷貝到手機 Library/Frameworks
目錄下替換原來的。
非越獄裝置整合Reveal
如果在開發中整合 Reveal
直接使用 CocoaPods/">CocoaPods
即可,在 Podfile
檔案加入以下內容:
//只在Debug模式下開啟 pod 'Reveal-SDK', :configurations => ['Debug']
之後執行 pod install
即可整合。
如果想在非越獄裝置檢視其它App的介面結構,需要使用 MonkeyDev 工具輔助完成。
首先安裝MonkeyDev,安裝在GitHub倉庫有文件。
非越獄裝置整合 Reveal
還需要目標App的脫殼 ipa
包。具體步驟檢視文章:
Cycript配置
Cycript 是允許開發者使用 Objective-C++
和 Javascript
組合語法檢視及修改執行時APP記憶體資訊的工具。
在越獄裝置上安裝
Cycript
是 saurik
提供的工具,在 Cydia
中搜索 Cycript
並安裝即可。
安裝完成後,用SSH登入裝置輸入 cycript
命令,就可以進入互動介面。
在越獄裝置上,可以使用一些命令注入目標程序,除錯目標函式。下面例子:指令碼注入到SpringBoard(桌面)中,使其彈出一個提示框。
iPad:~ root# cycript -p SpringBoard cy# var alert = [[UIAlertView alloc] initWithTitle:@"Hello" message:@"Hello, wold!" delegate:nil cancelButtonTitle: @"cancel" otherButtonTitles: nil] #"<UIAlertView: 0x1348bd1f0; frame = (0 0; 0 0); layer = <CALayer: 0x1321c89b0>>" cy# [alert show]
這是《iOS應用逆向與安全》中給出的一個簡單的例子。
Cycript
分析應用
上面例子中使用了一條命令 cycript -p SpringBoard
,通過該命令可以除錯指定APP。該命令有兩種使用方式,除了上面的 cycript -p 程式名稱
,還可以通過 cycript -p 程式程序ID
。注意這裡的程式的名稱並不是APP的名稱。
檢視程式的名稱和程序ID可以通過安裝一個外掛 adv-cmds
。通過它使用 ps
命令檢視當前執行程式的程序ID及可執行檔案的路徑。
安裝完成後,通過 ps -A
命令檢視當前裝置的程序ID和可執行檔案的路徑。同時,支援關鍵詞搜尋 ps -A | grep 關鍵詞
。
例如,檢視簡書的路徑和程序ID
由於程式的程序ID是會發生變換的推薦使用名稱。
下面就以簡書為例,學習如何使用 cycript
的使用。
檢視應用資訊
cy# NSHomeDirectory() // 沙盒路徑 cy# NSBundle.mainBundle().bundleIdentifier //BundleID cy# NSBundle.mainBundle().bundlePath //mainBundlePath cy# NSSearchPathForDirectoriesInDomains (NSDocumentDirectory , NSUserDomainMask , YES)[0] // Document Path cy# NSSearchPathForDirectoriesInDomains (NSCachesDirectory , NSUserDomainMask , YES)[0] // cache Path
檢視 APP
的 Application
資訊,例如:檢視簡書的 Application
物件,為自定義的 HGApplication
。
cy# UIApp # "<HGApplication: 0x154d49910>"
檢視 rootViewController
。
cy# UIApp.keyWindow .rootViewController #"<HGTabBarController: 0x155006200>"
還可以使用地址檢視資訊。例如:檢視 HGTabBarController
的 view
。
cy# #0x155006200.view #"<UILayoutContainerView: 0x154fca480; frame = (0 0; 1024 768); autoresize = W+H; layer = <CALayer: 0x154f65a20>>"
另外Cycript提供了 choose()
函式選擇某個類的例項陣列。例如:學習簡書中所有的Button類的所有例項陣列。
cy# choose(UIButton) [#"<UIButton: 0x157210600; frame = (0 8.5; 685 16); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x15705f020>>", #"<HGAvatarButton: 0x15724ead0; baseClass = UIButton; frame = (16 14.5; 45 45); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1572088b0>>".....]
以上是 cycript
的基本用法。
cycript
高階用法
每次要輸入那麼多的程式碼是在有點麻煩,能不能將常用的程式碼封裝起來呢?答案是肯定的。
Cycript本身是支援載入自己的指令碼的,可以通過 @import
命令載入。例如:載入 mjscript 指令碼。
cy# @import mjcript
關於如何將自己學的指令碼新增到手機上檢視 【越獄-逆向】基於Cycript實現的一些實用函式 文件,對如何新增,如何使用寫的比較詳細,這裡就不再重複贅述。
Class-dump
本節學習如何使用工具匯出第三方App的標頭檔案,學習前需要補充點基礎知識。
Mach-O檔案
想讓程式在裝置上執行起來,需要將寫好的程式碼生成可執行檔案這樣才能被作業系統所理解。比如,在 Linux
下可執行檔案的格式是 ELF
,在 Window
中可執行檔案是 PE32/PE32+
,而在 MAC
和 iOS
中是 Mach-O
格式。
Mach-O的組成結構如下圖:
可以看的出 Mach-O 主要由 3 部分組成:
- Mach-O 頭(Mach Header):這裡描述了 Mach-O 的 CPU 架構、檔案型別以及載入命令等資訊;
- 載入命令(Load Command):描述了檔案中資料的具體組織結構,不同的資料型別使用不同的載入命令表示;
- 資料區(Data):Data 中每一個段(Segment)的資料都儲存在此,段的概念和 ELF 檔案中段的概念類似,都擁有一個或多個 Section ,用來存放資料和程式碼。
如何獲取Mach-O檔案,在 App Store
中下載應用 .ipa
改成 .zip
格式,之後解壓縮會在裡面發現一個應用同名的檔案。
下面是簡書的Mach-O檔案:

Class-dump使用
class-dump 的作用就是把 Mach-O
檔案的class資訊匯出來生成標頭檔案。
下載後將其中的 class-dump
拷貝到 /usr/local/bin
目錄下,就可以在終端使用 class-dump
命令。
終端輸入 class-dump
:
class-dump 3.5 (64 bit) (Debug version compiled Sep 17 2017 16:24:48) Usage: class-dump [options] <mach-o-file> where options are: -ashow instance variable offsets -Ashow implementation addresses --arch <arch>choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64, armv6, armv7, armv7s, arm64) -C <regex>only display classes matching regular expression -f <str>find string in method name -Hgenerate header files in current directory, or directory specified with -o -Isort classes, categories, and protocols by inheritance (overrides -s) -o <dir>output directory used for -H -rrecursively expand frameworks and fixed VM shared libraries -ssort classes and categories by name -Ssort methods by name -tsuppress header in output, for testing --list-archeslist the arches in the file, then exit --sdk-iosspecify iOS SDK version (will look for /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS<version>.sdk or /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS<version>.sdk) --sdk-macspecify Mac OS X version (will look for /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX<version>.sdk or /Developer/SDKs/MacOSX<version>.sdk) --sdk-rootspecify the full SDK root path (or use --sdk-ios/--sdk-mac for a shortcut)
安裝成功,可以解析標頭檔案方法很簡單,常用指令。
class-dump -H mach-o路徑 -o 標頭檔案儲存路徑
以簡書App為例,使用之前砸殼的 ipa
檔案,找到裡面的 Mach-O
檔案。
class-dump -H Hugo -o ./Header
在當前目錄中會生成Header資料夾,裡面包含所有的標頭檔案。
參考文章
- Mach-O 檔案格式探索
- 趣探 Mach-O:檔案格式分析
- 《iOS應用逆向與安全》作者:劉培慶