iOS逆向攻防實戰(zhàn)

前言

本文是自己對iOS逆向工程領(lǐng)域所學的一個總結(jié)璃饱,文中所用的例子僅為學習研究使用与斤。


1. 逆向工程是什么?

從iOS應(yīng)用的功能或行為入手荚恶,通過脫殼撩穿、運行時分析、靜態(tài)分析谒撼、動態(tài)調(diào)試食寡、Hook、注入等一系列技術(shù)手段廓潜,推導出目標文件的結(jié)構(gòu)抵皱、流程、算法辩蛋、代碼等呻畸,稱為“iOS應(yīng)用逆向工程。

iOS逆向工程包括但不限于以下內(nèi)容:

2. 為什么要學習逆向工程悼院?

通常我們對某個APP進行逆向是為了在沒有源代碼的情況下了解這個APP的結(jié)構(gòu)或該APP某個關(guān)鍵功能的代碼實現(xiàn)等伤为,比如可以針對某個第三方APP進行界面布局或者功能邏輯的分析等。

本文將介紹iOS逆向領(lǐng)域中的一些常用攻防技術(shù)据途,運用這些技術(shù)來分析第三方APP中存在的一些安全問題并且給出防御方案绞愚。

3. 如何開始逆向?

首先我們需要準備一臺越獄手機昨凡。由于iOS平臺存在著沙盒機制爽醋,沙盒的原理是把應(yīng)用程序生成和修改的文件重定向到自身文件夾中,在沙盒機制下便脊,每個程序之間的文件夾不能互相訪問蚂四。所以非越獄手機無法了解它的內(nèi)部結(jié)構(gòu)、運行時機制等。

越獄后推薦安裝的插件 (越獄后會自動安裝一個叫做 Cydia的應(yīng)用遂赠,通過Cydia安裝插件) :

Cydia Substrate :逆向必備基本框架久妆,封裝了很多函數(shù),加入了安全的防崩潰保護機制跷睦,使插件開發(fā)變得簡單高效筷弦。

AFC2:用于激活助手類工具對iOS設(shè)備所有路徑的訪問權(quán)限。

adv-cmds:提供ps命令抑诸,用于查看當前運行進程的PID以及應(yīng)用的路徑烂琴。

AppSync Unified:用來繞過系統(tǒng)對應(yīng)用的簽名驗證,可以隨意安裝和運行脫殼后的ipa奸绷。

Filza File Manager:可以在iPhone上自由訪問iOS文件系統(tǒng)层玲。

NewTerm 2:能運行在手機上的終端工具。

4. 脫殼

iOS端App在上線之前會由蘋果商店進行FairPlayDRM數(shù)字版權(quán)加密保護(稱為“加殼”)润绵。

4.1. 什么是加殼线椰?


利用特殊的算法,對可執(zhí)行文件的編碼進行改變(比如壓縮授药、加密)士嚎,以達到保護程序代碼的目的。

要對應(yīng)用進行分析悔叽,就必須先解密(稱為“脫殼”)莱衩,從而得到原始未加密的二進制文件。

4.2. 怎么脫殼娇澎?

iOS中有很多好用的脫殼工具笨蚁,比如Clutchdumpdecrypted趟庄、AppCrackr括细、Crackulous。

以dumpdecrypted為例進行脫殼戚啥,流程如下:

a. 首先我們要生成“砸殼”用的動態(tài)庫dumpdecrypted.dylib奋单;

b. 到越獄手機上尋找要“砸殼”的app路徑(通過ssh連接設(shè)備,在終端用ps -e | grep wordios命令獲取設(shè)備當前運行的所有應(yīng)用信息中名字包括wordios的應(yīng)用猫十,我們可以找到wordios的運行路徑览濒;

c. 使用Cycript注入wordios進程呆盖,然后輸入以下指令獲取Document目錄


d. 然后通過愛思助手進入該目錄,將dumpdecrypted.dylib拷貝到該目錄下贷笛;

e. 終端進入該目錄应又,執(zhí)行下方命令:

DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/containers/Bundle/Application/48C8B703-726F-4304-89E8-7D6F725792F4/wordios.app/wordios

f. 執(zhí)行命令后會生成已脫殼的可執(zhí)行文件,后綴名為.decrypted乏苦;


g. 通過MachOView工具分析株扛,LC_ENCRYPTION_INFO_64 中的Crypt ID 為0,說明脫殼成功汇荐。


5. 攻

5.1. 攻擊手段一:運行時分析

運行時分析是常用的攻擊手段洞就,具體方案或工具有Cycript / Reveal / LookinLoader / Flex / class-dump等。

5.1.1. Cycript

Cycript是一款腳本語言拢驾,混合了OC與JS語法解釋器奖磁,能夠探測和修改運行中的應(yīng)用程序,主要用于注入目標程序來實現(xiàn)運行時調(diào)試繁疤,在重啟程序后所有的修改會失效。

利用Cycript向目標App注入代碼秕狰,從表面現(xiàn)象入手來獲取當前的界面布局及控制器稠腊,從而定位可疑方法或函數(shù),然后進行各種調(diào)用測試鸣哀,最終定位被逆向功能的入口架忌。

安裝方法: 越獄設(shè)備直接在Cydia中安裝

使用方法:
a. 注入目標程序,例如注入運行中的wordios我衬;

b. 使用Cycript語法進行運行時分析叹放。

實例一:

查看wordios的BundleId / APP運行路徑 / DocumentPath / CachePath / 當前的KeyWindow / 當前控制器 / 視圖層級等等

其中jjcript是我事先封裝好的一個接口文件,部分接口實現(xiàn)如下:

實例二:獲取按鈕點擊事件

Cycript還可以獲取某個按鈕的點擊事件挠羔,也就是方法名井仰,這對我們分析代碼邏輯有很大的幫助合是,比如我們在使用某社交APP時,使用某個付費功能臀稚,如果你是非會員就會彈出一個會員引導彈框失乾,這時候我們可以通過分析這個點擊事件,看能否繞過付費的代碼邏輯直接使用付費功能刀荒。


5.1.2. Reveal / LookinLoader

Reveal / LookinLoader 是一款強大的UI調(diào)試工具柴罐,可以調(diào)試任何一個iOS應(yīng)用详炬。它可以在運行時查看App的界面層級關(guān)系诗良,還可以實時修改程序界面秀又,不用重新運行程序就可以看到修改之后的效果珊皿,免去了每次修改代碼后又重新啟動的過程腺律。逆向工程里面通常用Reveal / LookinLoader來快速定位感興趣的控件什乙,進而找到控制器肄扎,再用Cycript進行事件分析拦赠。

(Reveal)

(LookinLoader)

5.1.3. Flex

Flex是一個iOS應(yīng)用的內(nèi)部調(diào)試工具沪羔。當它加載時饥伊,會向目標程序上方添加一個懸浮的工具欄,通過這個工具欄可以查看和修改視圖的層級結(jié)構(gòu)蔫饰、動態(tài)修改類的屬性琅豆、動態(tài)調(diào)用實例和方法、動態(tài)查看類和框架以及動態(tài)修改UI等篓吁。


5.1.4. class-dump

class-dump是一個命令行工具茫因,它利用Object-C語言的運行時特性將二進制文件中的類、方法及屬性等信息導出為頭文件杖剪。

下載方法:從http://stevenygard.com/projects/class-dump/下載最新安裝包冻押,雙擊打開驰贷,將“class-dump”拖動到/usr/local/bin目錄下即可使用。

以wordios為例來講解它的使用方法:

class-dump -S -s -H wordios.decrypted -o ./Headers


5.2. 攻擊手段二:監(jiān)聽和攔截函數(shù)調(diào)用

Frida是一個跨平臺的輕量級Hook框架洛巢,支持所有主流操作系統(tǒng)括袒,它可以幫助逆向研究人員對指定的進程進行分析。它主要提供了精簡的Python接口和功能豐富的JS接口稿茉,除了使用自身的控制臺交互以外锹锰,還可以利用Python將JS腳本庫注入目標進程。使用Frida可以獲取進程詳細信息狈邑、攔截和調(diào)用指定函數(shù)城须、注入代碼、修改函數(shù)米苹、從iOS應(yīng)用程序中dump類和類方法信息等糕伐。

Frida能實現(xiàn)很多功能,以下介紹幾種比較常用的功能:

5.2.1. 獲取可用設(shè)備列表

frida-ls-devices

圖中顯示有一個連接usb接口名為iPhone的設(shè)備蘸嘶。

5.2.2. 獲取設(shè)備進程列表

frida-ps -U //-U 代表連接到 USB 設(shè)備


圖中顯示該設(shè)備正在運行的進程有文檔表格編輯良瞧,其id為2432。

5.2.3. 結(jié)束設(shè)備上的某個進程

frida-kill -U 2432//2432就是上面所獲取的文檔表格編輯的id


在終端運行之后就會立即殺死文檔表格編輯進程训唱。

5.2.4. 跟蹤函數(shù) / 方法調(diào)用

跟蹤函數(shù): 比如跟蹤id為9218的進程中的compress函數(shù):

frida-trace -U -i compress 9218

當觸發(fā)該方法時會在終端輸出褥蚯。

跟蹤 OC 方法: 比如跟蹤文檔表格編輯中CourseVC 控制器中的viewWillAppear方法

frida-trace -U -m "-[wordios.CourseVC viewWillAppear*]" 文檔表格編輯 //由于該app做了代碼混淆處理,經(jīng)過分析况增,類名需要wordios.CourseVC這樣調(diào)用才行赞庶。



每次進入CourseVC 界面的時候就會觸發(fā)viewWillAppear,如圖終端中輸出了2次澳骤,代表CourseVC 觸發(fā)了2次viewWillAppear方法歧强。

5.2.5. 攔截某個類的所有方法

比如以下場景,文檔表格編輯的教程界面为肮,點擊Word文檔之后摊册,如果是非會員就會彈出解鎖功能界面;那么如果我想知道從點擊Word文檔到跳轉(zhuǎn)解鎖功能界面的這個過程中會調(diào)用到哪些函數(shù)颊艳,我們就可以利用frida進行跟蹤茅特。


首先使用LookinLoader找到Word文檔按鈕所在的控制器。

如上圖所示棋枕,所在控制器為CourseVC白修。

編寫js腳本對CourseVC類的所有方法進行攔截

然后用frida加載該js腳本

frida -U -l wordios.js 文檔表格編輯


運行腳本后,效果如上圖所示戒悠。

關(guān)于Frida更多的功能請參考官網(wǎng)https://frida.re/docs/home/

5.3. 攻擊手段三:靜態(tài)分析

靜態(tài)分析是在程序尚未運行的狀態(tài)下進行的逆向分析熬荆。主要使用反匯編、偽代碼、流程圖卤恳、代碼修改等方式累盗,常用的靜態(tài)分析工具有Hopper、IDA Pro等突琳。

Hopper / IDA Pro能夠?qū)ach-O文件的機器語言代碼反編譯成匯編代碼若债、OC偽代碼或者swift偽代碼。

Hopper/IDA Pro的地址都是未使用ASLR的VM Address拆融。

以wordios為例蠢琳,通過Hopper我們可以查看wordios可執(zhí)行文件里的所有方法。如果我們對某個方法感興趣镜豹,只要一搜就能看到傲须,但只能看到匯編代碼或者OC偽代碼實現(xiàn);我們看到該app有很多比如sub_10004f850這樣的函數(shù)名趟脂,說明該app對大量方法名使用了代碼混淆的防護手段泰讽。

5.4. 攻擊手段四:動態(tài)分析

動態(tài)分析,簡單來說就是昔期,我們可以直接使用LLDB調(diào)試別人的程序已卸,在靜態(tài)分析中必須聯(lián)系上下文進行分析與猜測,而動態(tài)分析時只需要把相關(guān)寄存器或棧內(nèi)容打印出來便一目了然硼一,甚至可以直接修改返回值來驗證結(jié)果的準確性累澡。

LLDB只能運行在macOS上,若要調(diào)試iOS應(yīng)用般贼,需要先在設(shè)備上運行一個叫做debugserver的工具愧哟。

debugserver扮演服務(wù)器的角色,把在macOS端執(zhí)行的各種LLDB指令傳遞給設(shè)備端哼蛆,并把設(shè)備端的結(jié)果反饋到macOS終端翅雏,這種調(diào)試方式稱為遠程調(diào)試。


5.4.1. 如何配置debugserver人芽?

如果當前的iOS設(shè)備進行過真機調(diào)試,那么debugserver會被自動安裝到Develop/usr/bin目錄绩脆,可以通過愛思助手將其導出到macOS上

由于debugserver缺少task_for_pid權(quán)限萤厅,所以只能調(diào)試自己的應(yīng)用,如果要調(diào)試第三方應(yīng)用靴迫,就需要對debugserver進行處理惕味,在iOS11運行還需要加上platform-application權(quán)限。

具體步驟:

a. 在導出的debugserver同級目錄下創(chuàng)建一個名為“ent.xml”的文件玉锌,并輸入以下內(nèi)容


b. 在終端使用codesign進行簽名

codesign -f -s - --entitlements ent.xml ./debugserver

c. 將簽名后的debugserver復制到設(shè)備 /usr/bin/ 目錄下名挥,并添加執(zhí)行權(quán)限

chmod +x /usr/bin/debugserver

把debugserber復制到“/usr/bin/”目錄的好處是,在任意目錄下都可以直接運行debugserver主守。

  • 與LLDB建立連接

開啟debugserer

// *:端?號

// *代表接受任意IP的連接禀倔,使?iPhone的某個端?啟動debugserver服務(wù)(只要不是保留端?號就?)

// -a 進程

// 輸?APP的進程信息(進程ID或者進程名稱)

$ debugserver *:端?號 -a 進程

a. 10011端口映射

b. 讓設(shè)備中的debugserver附加到 wordios 進程

c. 打開一個新的終端榄融,使LLDB連接到debugserer

比如調(diào)試 [wordios.CourseVC showMore:],只要知道方法的起始地址救湖,就可以給方法設(shè)置斷點愧杯,我們可以在Hopper中找到這個方法的地址。

但是由于ASLR機制鞋既,使得進程每次啟動時力九,地址空間都會被簡單地隨機化,相當于在Mach-O起始地址前會增加一段隨機地址值邑闺,所以Hopper中的方法地址并不是真正的地址

真正的地址 = ASLR偏移值 + Hopper方法地址

用以下命令查看應(yīng)用的ASLR偏移值

image list -f -o

如下圖跌前,偏移值為 0x0000000000398000

在Hopper找到showMore:的靜態(tài)地址 0x000000010006b9ec

計算出方法的真實地址,打斷點 (breakpoint set --address ASLR偏移地址+方法靜態(tài)地址)陡舅。

breakpoint set --address 0x0000000000398000+0x000000010006b9ec

5.5. 攻擊手段五:Theos

Theos是一個跨平臺的越獄開發(fā)工具包抵乓,它為開發(fā)者準備好了一些代碼模板、預(yù)置了一些基本的Makefile腳本蹭沛,方便開發(fā)插件臂寝。

Theos相當于對CydiaSubstrate的封裝,因此能實現(xiàn)對Objective-C運行時的Hook摊灭,也能實現(xiàn)對C語言函數(shù)的Hook咆贬。

簡單來說,Theos可以通過修改二進制文件里某個方法的實現(xiàn)帚呼,以達到破解的目的掏缎。

以上是逆向工程中常用的攻擊手段,有一點需要注意的是煤杀,當我們成功修改完可執(zhí)行文件之后眷蜈,直接替換原文件安裝到手機上是運行不了,這時候就需要用到重簽名了沈自。

5.5.1. 重簽名

一旦修改了應(yīng)用的二進制文件酌儒,或者增加、修改了應(yīng)用里面的資源枯途,應(yīng)用本身的簽名就會被破壞忌怎,由于iOS內(nèi)核中強制部署了許多代碼簽名機制,運行修改后的應(yīng)用會閃退甚至安裝不成功酪夷,這樣就可以避免攻擊者在用戶的設(shè)備上傳播并運行不受信的代碼榴啸。

如果希望將破壞了簽名的安裝包,安裝到非越獄的手機上晚岭,需要對安裝包進行重簽名的操作鸥印。

有兩個注意點:

a. 安裝包中的可執(zhí)行文件必須是經(jīng)過脫殼的,重簽名才會有效。

b. .app包內(nèi)部的所有動態(tài)庫(.framework库说、.dylib)狂鞋、AppExtension(PlugIns文件夾,拓展名是appex)璃弄、WatchApp(Watch文件夾)都需要重新簽名

重簽名步驟:

a. 準備一個embedded.mobileprovision文件(必須是付費證書產(chǎn)生的要销,appid、device一定要匹配)夏块,并放入.app包中疏咐。可以通過Xcode自動生成脐供,然后在編譯后的APP包中找到浑塞,也可以去開發(fā)者證書網(wǎng)站生成下載。

b. 從embedded.mobileprovision文件中提取出entitlements.plist權(quán)限文件政己。

在終端敲以下命令即可提取

security cms -D -i embedded.mobileprovision > temp.plist

/usr/libexec/PlistBuddy -x -c 'Print :Entitlements' temp.plist > entitlements.plist

查看可用的證書

security find-identity -v -p codesigning

對.app內(nèi)部的動態(tài)庫酌壕、AppExtension等進行簽名

codesign -fs 證書ID xxx.dylib

對.app包進行簽名

codesign -fs 證書ID --entitlements entitlements.plist xxx.app

也可以使用一些帶有 UI 的重簽名工具。例如:

iOS App Signer (https://github.com/DanTheMan827/ios-app-signer

iOS App Signer可以對.app重簽名打包成ipa歇由,需要在.app包中提供對應(yīng)的embedded.mobileprovision文件卵牍。

iReSign (https://github.com/maciekish/iReSign

iReSign可以對ipa進行重簽名,需要提供entitlements.plist沦泌、embedded.mobileprovision文件的路徑糊昙。

重簽名的過程中遇到的問題與注意點:

a. 只能對脫殼的可執(zhí)行文件進行重簽名。

b. 工具只能對ipa進行重簽名谢谦,app內(nèi)的動態(tài)庫释牺、AppExtension需要先手動重簽名,最后再使用工具進行ipa重簽名回挽。

c. 重簽名打包成ipa安裝到手機時如出現(xiàn)DeviceNotSupportB...錯誤没咙,應(yīng)該是info.plist文件里面的UISupportedDevices字段的問題,需要把這個字段去掉再重新打包千劈。

重簽名步驟總結(jié)(以文檔表格編輯為例)

a. 通過愛思助手等工具把文檔表格編輯的app包拷貝到電腦上

b. 把已脫殼的可執(zhí)行文件放到app里面替換原來的未脫殼的可執(zhí)行文件

c. 把新的描述性文件祭刚、需要注入的動態(tài)庫放進app包里面(與可執(zhí)行文件同一路徑)

d. 對app包里的所有動態(tài)庫、extension墙牌、framework袁梗、PlugIns進行重簽名(自己加的動態(tài)庫,改完CydiaSubstrate路徑再重簽名)

codesign -fs 證書ID 動態(tài)庫名字

e. 修改所有注入動態(tài)庫的查找路徑憔古,例如注入動態(tài)庫wordiosfree,需要將wordiosfree的查找路徑改成@executable_path/wordiosfree.dylib淋袖,如果動態(tài)庫wordiosfree還依賴其他動態(tài)庫鸿市,一般都要依賴CydiaSubstrate(libsubstrate)這個庫,所以還需要將CydiaSubstrate的查找路徑改為@loader_path/CydiaSubstrate.dylib(@loader_path/libsubstrate.dylib,需要注意的是焰情,一般是用這個陌凳,因為從手機終端導出來的CydiaSubstrate自動改名為libsubstrate,如果使用@loader_path/CydiaSubstrate.dylib會導致路徑錯誤閃退)

otool -L wordiosfree.dylib //查找動態(tài)庫所依賴的庫及其路徑

install_name_tool -change /Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate @loader_path/CydiaSubstrate wordiosfree.dylib //修改CydiaSubstrate的執(zhí)行路徑

f. 把動態(tài)庫wordiosfree注入到可執(zhí)行文件里面

insert_dylib @executable_path/wordiosfree.dylib wordios wordios --all-yes --weak

g. 把info.plist里的UISupportedDevices字段刪掉

使用工具對app包進行重簽名并生成ipa文件内舟,再通過愛思助手安裝到手機上

6.

前面談到這么多種攻擊手段合敦,那么對應(yīng)的也存在很多的防御手段,比如數(shù)據(jù)加密(字符串验游、網(wǎng)絡(luò)數(shù)據(jù)充岛、敏感數(shù)據(jù)等)、應(yīng)用加殼(二進制加密耕蝉,iOS上傳appstore會自動加殼崔梗,但早已被破解)、代碼混淆(類名垒在、方法名蒜魄、代碼邏輯等)俊抵、反調(diào)試趁尼、反注入、Hook檢測瓤逼、越獄檢測踢关、完整性檢測等伞鲫。

通過逆向大量市面上很多的APP,我發(fā)現(xiàn)大多數(shù)都沒有做太多的防護措施耘成,不過也有少數(shù)像抖音榔昔、微信這樣的知名APP就做了大量的防護措施”窬總之撒会,沒有防御的APP就像把源代碼暴露在別人面前一樣,漏洞百出师妙,存在著大量的安全隱患诵肛,所以我認為對APP做一些防護是非常有必要的,學習一些逆向知識默穴,還能提高我們的安全意識怔檩,在平時的開發(fā)過程中編寫代碼也會時時注意到什么樣的寫法是有漏洞的,什么樣的寫法才是安全的蓄诽。

接下來我會介紹幾種逆向領(lǐng)域里常用的防御手段薛训,也稱應(yīng)用加固。

6.1. 防御手段一:代碼混淆

iOS程序可以通過class-dump仑氛、hopper乙埃、IDA等獲取類名闸英、方法名、以及分析程序的執(zhí)行邏輯介袜。如果很容易被別人看到類名甫何、方法名是干嘛用的,就很容易被人破解遇伞。所以進行代碼混淆辙喂,將加大別人的分析難度。

在iOS中鸠珠,代碼混淆主要還是對源碼進行混淆巍耗,比如類名、方法名跳芳、協(xié)議名芍锦、屬性名。通過宏定義混淆飞盆,例如把Person這個類的名字混淆成abcd:

define Person abcd

如果直接將類名娄琉、方法名改成abcd什么的,確實可以混淆吓歇,但是自己維護也很麻煩孽水。

注意點:

● 不能用宏定義混淆系統(tǒng)方法

● 不能混淆init開頭的方法

● 如果xib、storyboard用到的內(nèi)容城看,需要修改一下女气,比如說控制器名用到了混淆,那么xib测柠、storyboard中用到名稱需要手動去修改一下炼鞠,因為系統(tǒng)是不會幫你換的(使用某些工具可以自動化替換)

● 不要什么都去混淆,因為混淆代碼太多上架會被拒轰胁,只混淆關(guān)鍵代碼

● 可以考慮將需要混淆的代碼就加個前綴谒主,這樣就跟正常代碼好區(qū)分

6.2. 防御手段二:反調(diào)試-ptrace

ptrace是一種對運行中的進程進行跟蹤和控制的手段,通過ptrace赃阀,一個ptrace可以動態(tài)地讀寫另一個進程的內(nèi)存和寄存器霎肯,包括指令空間、數(shù)據(jù)空間榛斯、堆棧以及所有的寄存器观游。同時,ptrace還提供了一個非常很有用的PT_DENY_ATTACH參數(shù)驮俗,用來告訴系統(tǒng)阻止調(diào)試器附加懂缕,所以,最常用的反調(diào)試就是通過調(diào)用ptrace來實現(xiàn)王凑。

參數(shù)1:要做的事情

參數(shù)2:要控制的進程ID

參數(shù)3:地址

參數(shù)4:數(shù)據(jù)


參數(shù)3和參數(shù)4都由參數(shù)1決定要傳遞的地址和數(shù)據(jù)提佣。

參數(shù)1的列表


調(diào)用方式:


效果:


當我們嘗試使用動態(tài)調(diào)試時吮蛹,會直接報segmentation fault:11錯誤。

6.3. 防御手段三:反注入

當自己編寫的dylib無法加載到目標應(yīng)用的時候拌屏,就表明此應(yīng)用做了反注入保護。我們可以通過Build Settings -> Signing -> Enable Hardened Runtime 改為YES术荤,或者Capabilities來設(shè)置倚喂。這樣在runtime的時候,會檢查注入庫的簽名與ipa的簽名是否一致瓣戚,簽名不一致就無法注入端圈。


以下鏈接是官方給出的解決方案:

https://developer.apple.com/documentation/security/hardened_runtime

6.4. 防御手段四:Hook檢測

iOS上的Hook方式主要就兩種,Method Swizzing和Inline Hook子库。

Method Swizzing的原理是替換IMP舱权,所以可以通過dladdr得到IMP地址所在的模塊信息進行判斷,示例如下:


Inline Hook的原理是通過修改函數(shù)的前N字節(jié)內(nèi)存仑嗅,使程序跳轉(zhuǎn)到自己編寫的函數(shù)宴倍,我們要做的就是檢測函數(shù)頭部若干字節(jié)是不是被修改。

6.5. 防御手段五:越獄檢測

很多應(yīng)用為了確保安全性需要對越獄環(huán)境進行檢測仓技,如果機器越獄了則不啟用某些敏感功能(比如微信的指紋支付功能鸵贬,在越獄狀態(tài)下就會自動關(guān)閉)。

具體方案:

6.5.1. 檢測越獄商店及其附屬文件

越獄環(huán)境幾乎都安裝了Cydia脖捻、Sileo及其附屬文件阔逼,可以用下列代碼檢測:

6.5.2. 嘗試讀取系統(tǒng)應(yīng)用列表

如果設(shè)備已經(jīng)越獄,就可以讀取到系統(tǒng)應(yīng)用列表的內(nèi)容地沮,以此來作為檢測依據(jù)嗜浮,可以用下列代碼檢測:

6.5.3. 檢測URLSchemes是否有效

URLSchemes是蘋果公司提供的用來跳轉(zhuǎn)到系統(tǒng)應(yīng)用或跳轉(zhuǎn)到其他應(yīng)用的一種機制。

這種機制提供了一種檢測越獄的思路:

如果能打開Cydia或其他非官方應(yīng)用摩疑,則說明已經(jīng)越獄危融,利用“- (BOOL)canOpenUrl:(NSURL *)url”方法來測試相應(yīng)應(yīng)用的URLSchemes是否有效就能判定。

6.6. 防御手段六:完整性檢測

完整性檢測可以確認目標文件是否被脫殼未荒、是否被靜態(tài)注入专挪、內(nèi)容是否被修改、是否被重簽名等片排。常見的方式有:

6.6.1. 加載命令檢測

為了使未越獄的設(shè)備也能順利使用插件寨腔,通常會在LoadCommand(加載命令)中增加一個LC_LOAD_DYLIB或者LC_LOAD_WEAK_DYLIB的方式來指向自己的動態(tài)庫路徑,從而實現(xiàn)注入功能率寡,這種方式通常也被稱為“靜態(tài)注入”迫卢。

記載命令檢測即檢測Mach-O文件的LoadCommand中的LC_LOAD_DYLIB或LC_LOAD_WEAK_DYLIB是否存在異常,代碼如下:

6.6.2. 代碼段檢測

代碼段檢測技術(shù)主要用來檢測“_TEXT, _text”是否被修改(當然也可以檢查其他的section)冶共,示例如下:

其中乾蛤,&_mh_execute_header指向Mach-O在內(nèi)存中的起始位置每界,getsectiondata函數(shù)返回指定Section的內(nèi)存地址及大小。

實際應(yīng)用中可以將正確的Hash值存到服務(wù)器或者加密后存到本地家卖,在進程啟動時進行比對眨层,如果不匹配則可以做一些邏輯處理。

6.6.3. 簽名信息檢測

被修改的應(yīng)用若要在非越獄機器上使用上荡,必要的一個環(huán)節(jié)就是對其重簽名趴樱。

簽名信息檢測就是檢測LC_CODE_SIGNATURE中的特征信息(比如TeamID)是否和用戶自己的相匹配。

7. 實戰(zhàn)案例:某即時通信軟件 - 猜拳和扔骰子代碼實現(xiàn)分析

7.1. 目標 App 介紹

本文的實戰(zhàn)目標是一款著名的即時通訊App酪捡,可以通過手機網(wǎng)絡(luò)發(fā)送表情包叁征,比如猜拳和扔骰子,這兩個是官網(wǎng)自帶的表情包逛薇,發(fā)出去之后先是有一個不停跳動的動畫捺疼,最后會停留在一個隨機的剪刀/石頭/布或者點數(shù),這一切看起來都是隨機的永罚,但是通過逆向我們是能夠?qū)崿F(xiàn)自動操控并且投出想要的結(jié)果的啤呼。

7.2. 尋找切入點

逆向一個App首先需要尋找切入點,在本案例中尤蛮,要想分析猜拳和扔骰子的實現(xiàn)媳友,我們首先得從UI層面入手,找出當前控制器产捞,然后監(jiān)聽點擊表情包之后的方法調(diào)用醇锚,找到關(guān)鍵方法,分析該方法的代碼實現(xiàn)坯临,并且尋找代碼漏洞焊唬,一旦找到可以hook的代碼邏輯,那么就可以實現(xiàn)我們想要的代碼邏輯了看靠。

7.3. 分析過程

使用Lookin我們可以知道當前控制器是BaseMsgContentViewController赶促,然后進一步分析界面:


可以看到,這是一個UICollectionViewCell挟炬,自然而然就會想到點擊它會觸發(fā)

以下代理方法:


- (void)collectionView:

(UICollectionView *)collectionView didSelectItemAtIndexPath:

(NSIndexPath *)indexPath;

我們可以通過斷點BaseMsgContentViewController類的didSelectItem...方法來分析代碼邏輯鸥滨,但還有另一種更加便捷的方法是直接監(jiān)聽BaseMsgContentViewController的所有方法調(diào)用,這里我使用的是Frida + js腳本去跟蹤發(fā)送骰子時該類所有的方法調(diào)用

-[BaseMsgContentViewController useTransparentNavibar]

-[BaseMsgContentViewController useTransparentNavibar]

-[BaseMsgContentViewController shouldInteractivePop]

-[BaseMsgContentViewController toolView]

-[BaseMsgContentViewController SendEmoticonMesssageToolView:]

-[BaseMsgContentViewController findNodeDataByLocalId:]

-[BaseMsgContentViewController addMessageNode:layout:addMoreMsg:]

-[BaseMsgContentViewController findNodeDataByLocalId:]

-[BaseMsgContentViewController getCurContentSizeHeight]

仔細觀察我們可以發(fā)現(xiàn)[BaseMsgContentViewController sendEmoticonMessageToolView:]這個方法有很大的幾率就是我們要找的關(guān)鍵方法谤祖,從字面上看是發(fā)送表情信息的意思婿滓。然后繼續(xù)編寫腳本

使用frida加載該腳本,就可以打印出該方法的堆棧信息(去除了不必要的地址信息):

-[BaseMsgContentViewController SendEmoticonMesssageToolView:]

    Backtrace:

    -[MMInputToolView didSelectorSelfDefinedEmotcion:]

    -[EmoticonBoardView onTapEmoticonWrap:atIndex:maxCountPerLine:fromSection:]

    -[EmoticonBoardCrossCollectionController onEmoticonPageCellTapEmoticonWrap:atIndex:pid:maxCountPerLine:]

    -[EmoticonBoardCrossCollectionEmoticonPageCell collectionView:didSelectItemAtIndexPath:]

    -[UICollectionView _selectItemAtIndexPath:animated:scrollPosition:notifyDelegate:deselectPrevious:]

    -[UICollectionView touchesEnded:withEvent:]

    UIKitCore!forwardTouchMethod

    UIKitCore!-[UIResponder touchesEnded:withEvent:]

    UIKitCore!forwardTouchMethod

    UIKitCore!-[UIResponder touchesEnded:withEvent:]

    UIKitCore!forwardTouchMethod

    UIKitCore!-[UIResponder touchesEnded:withEvent:]

    UIKitCore!_UIGestureEnvironmentUpdate

    UIKitCore!-[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:]

UIKitCore!-[UIGestureEnvironment _updateForEvent:window:]

    UIKitCore!-[UIWindow sendEvent:]

經(jīng)過動態(tài)分析之后粥喜,我們順利找出點擊骰子時的堆棧調(diào)用信息凸主,接下來我們就運用靜態(tài)分析的方式來分析這幾個方法的源代碼實現(xiàn),使用hopper去加載已脫殼的二進制文件额湘。

我們首先分析-[EmoticonBoardCrossCollectionController onEmoticonPageCellTapEmoticonWrap:atIndex:pid:maxCountPerLine:]

這個方法卿吐,因為它是didSelectItemAtIndexPath之后調(diào)用的旁舰。

通過分析該方法的偽代碼,我們可以知道這個方法沒做什么實事嗡官,只是做了一個代理轉(zhuǎn)發(fā)箭窜,接著看-[EmoticonBoardView onTapEmoticonWrap:atIndex:maxCountPerLine:fromSection:]

這個方法的偽代碼實現(xiàn),由于這個方法的代碼邏輯比較多衍腥,所以簡單描述下這個方法做了什么事情绽快,該方法判斷選擇的表情包是否為自定義表情,如果是就異步上傳紧阔,最終調(diào)用-[MMInputToolView didSelectorSelfDefinedEmotcion:]方法,

我們知道了傳入的參數(shù)是r27续担,具體r27是什么類型我們并不清楚擅耽,但從偽代碼的上下文中可以發(fā)現(xiàn)r27有調(diào)用以下幾個方法:

[r27 m_emojiInfo]
[r27 m_isAsyncUpload]
[r27 attachObject:r20 forKey:@"emoticonpageid"]

再通過hopper去尋找這些方法對應(yīng)的類

由此可知傳入的參數(shù)是CEmoticonWrap類,而骰子的結(jié)果應(yīng)該是保存在這個類中物遇,接著繼續(xù)分析-[MMInputToolView didSelectorSelfDefinedEmotcion:]方法的偽代碼實現(xiàn):

這個方法的實現(xiàn)比較簡單乖仇,也只是進行了一個代理轉(zhuǎn)發(fā)操作,接著分析-[BaseMsgContentViewController SendEmoticonMesssageToolView:]


這個方法仍然是進行了代理轉(zhuǎn)發(fā)询兴,繼續(xù)分析-[BaseMsgContentLogicController SendEmoticonMessage]


這里用到了m_uiGameType來判斷乃沙,而m_uiGameType是arg2的屬性,由上可知诗舰,arg2是CEmoticonWrap類警儒,使用class-dump把該二進制文件所有的頭文件導出來,然后找到CEmoticonWrap這個類的頭文件:


我們打印一下arg2眶根,編寫腳本蜀铲,打印該參數(shù)的所有屬性值:

<CEmoticonWrap: self.m_uiType=1, self.m_bCanDelete=1, self.m_uiGameType=2, self.m_nsAppID=(null), self.m_extFlag=0, self.m_nsThumbImgPath=(null), self.m_lastUsedTime=0, self.m_isAsyncUpload=0, self.m_isRemoteRecommed=0, self.m_isLastSended=0, self.m_query=(null), self.m_emojiInfo=<EmojiInfoObj: 0x281bbd950> {

    activityId = <nil>;

    aesKey = <nil>;

    attachedText = <nil>;

    attachedTextColor = <nil>;

    authkey = <nil>;

    designerId = <nil>;

    disableExtern = 0;

    encryptUrl = <nil>;

    externMd5 = <nil>;

    externUrl = <nil>;

    lensId = <nil>;

    linkId = <nil>;

    md5 = "dice_emoticon_md5";

    productId = "custom_emoticon_pid";

    thumbUrl = <nil>;

    tpUrlString = <nil>;

    url = <nil>

}

其中m_uiGameType等于2,而且這個類的其他大部分屬性包括圖片url都還沒有賦值属百,可以判斷到目前為止记劝,骰子的結(jié)果還沒有出來。

如果m_uiGameType不等于0就調(diào)用-[GameController sendGameMessage:toUsr:]方法


然后又調(diào)用了-[GameController SetGameContentForMsgWrap]

分析到這里族扰,終于找到突破口了厌丑!

紅圈中的代碼邏輯是,首先m_uiGameType 不等于0渔呵,如果m_uiGameType等于1就走if怒竿,其他就走else,從上文可知厘肮,m_uiGameType為2愧口,根據(jù)這個邏輯,我們可以大膽猜測类茂,m_uiGameType其實就是猜拳和扔骰子的類型耍属,其中猜拳是1托嚣,扔骰子是2,經(jīng)過驗證厚骗,點擊猜拳時m_uiGameType確實是1示启,那么我們可以得出,這段代碼就是這兩種游戲結(jié)果的計算公式了领舰。

如果m_uiGameType = 1(猜拳):

r20 = 1 + random() - random() / 3 * 3 = 1 + random() % 3

如果m_uiGameType = 2(扔骰子):

r20 = 4 + random() - random() / 6 * 6 = 4 + random() % 6

觀察公式計算可得夫嗓,猜拳的取值范圍是1-3,而扔骰子的取值范圍是4-9冲秽,剛好對應(yīng)著石頭剪刀布和6個點數(shù)舍咖。

到這里為止,我們已經(jīng)完成了猜拳和扔骰子的代碼邏輯分析了锉桑。如果想要進一步的修改最后的結(jié)果排霉,只要把唯一的變量random()的值hook掉就可以了,由于random()是C語言函數(shù)民轴,它不像hook OC方法那樣可以利用運行時機制提供的API來直接替換方法實現(xiàn)攻柠,所以Method Swizzling對它是無效的,需要使用Inline Hook才能達到目的后裸,一般常用的有MSHookFunction瑰钮、fishhook、HookZz等微驶,需要注意的是MSHookFunction只能在越獄手機上生效浪谴,如果想要在非越獄手機上生效,推薦使用fishhook祈搜。

7.4. 案例流程梳理

案例選擇了一個即時通訊app较店,確定需要逆向的功能-猜拳和扔骰子,然后從UI層面下手尋找切入點容燕,找到當前控制器以及對應(yīng)的控件類型梁呈,接著利用frida監(jiān)聽當前控制器的方法調(diào)用,拿到方法調(diào)用之后找到關(guān)鍵方法蘸秘,打印該方法的堆棧調(diào)用官卡,使用hopper靜態(tài)分析堆棧調(diào)用中涉及的每一個方法的實現(xiàn)代碼,再結(jié)合動態(tài)分析打印方法的參數(shù)值醋虏,找到關(guān)鍵代碼寻咒,最終還原了該功能的實現(xiàn)代碼。

以上就是一次完整的逆向過程颈嚼,看似簡單毛秘,實際操作過程中會遇到大量的坑欲鹏,并且逆向領(lǐng)域比較小眾氮昧,遇到問題可能難以在網(wǎng)上找到答案宪郊,所以整個過程非常消耗時間昼激,但是逆向成功之后會收獲很多,逆向工程與正向開發(fā)相反抹恳,它讓你從另外一個角度去看待軟件開發(fā)员凝,窺探代碼的本質(zhì)。

8. 總結(jié)

本文分享了iOS逆向工程的大部分知識和技術(shù)奋献,由于篇幅有限健霹,開篇中的思維導圖有某些知識點沒有展開細講,主要還是講解逆向工程中的攻擊手段和防御手段瓶蚂。

攻擊手段有應(yīng)用脫殼、運行時分析窃这、靜態(tài)分析、動態(tài)調(diào)試、修改可執(zhí)行文件畔裕、注入動態(tài)庫等。

防御手段有代碼混淆扮饶、反調(diào)試具练、反注入、Hook檢測甜无、越獄檢測扛点、完整性檢測等。

總之岂丘,iOS逆向工程中攻擊的基本流程就是:先想盡一切辦法尋找切入點(突破口)陵究,接著通過靜態(tài)分析與動態(tài)調(diào)試相結(jié)合、跟蹤和分析目標程序的核心代碼奥帘、理解其設(shè)計思路等铜邮,從而還原出相似代碼。

幾乎所有的防御手段都是根據(jù)攻擊手段來布置的,需要注意的是松蒜,即使做了這些防御手段扔茅,也不代表一定不會被破解,世界上沒有十全十美的APP牍鞠,只要黑客技術(shù)夠強咖摹,總能發(fā)現(xiàn)一些漏洞,我們能做的只有做盡可能多的防御措施难述,迫使攻擊者放棄破解的念頭萤晴。

在文章的最后,通過逆向第三方App中的一個有趣的功能去把所有介紹的逆向技術(shù)真正地運用到實戰(zhàn)當中胁后。

9. 參考資料

a. 書籍:《iOS應(yīng)用逆向與安全之道》

b. 視頻:《iOS底層原理》

c. 參考鏈接:https://iosre.com/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末店读,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子攀芯,更是在濱河造成了極大的恐慌屯断,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侣诺,死亡現(xiàn)場離奇詭異殖演,居然都是意外死亡,警方通過查閱死者的電腦和手機年鸳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門趴久,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人搔确,你說我怎么就攤上這事彼棍。” “怎么了膳算?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵座硕,是天一觀的道長。 經(jīng)常有香客問我涕蜂,道長华匾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任机隙,我火速辦了婚禮瘦真,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘黍瞧。我一直安慰自己诸尽,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布印颤。 她就那樣靜靜地躺著您机,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上际看,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天咸产,我揣著相機與錄音,去河邊找鬼仲闽。 笑死脑溢,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的赖欣。 我是一名探鬼主播屑彻,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼顶吮!你這毒婦竟也來了社牲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤悴了,失蹤者是張志新(化名)和其女友劉穎搏恤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體湃交,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡熟空,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了搞莺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痛阻。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腮敌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情俏扩,我是刑警寧澤糜工,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站录淡,受9級特大地震影響捌木,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嫉戚,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一刨裆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彬檀,春花似錦帆啃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春疯坤,著一層夾襖步出監(jiān)牢的瞬間报慕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工压怠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留眠冈,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓菌瘫,卻偏偏與公主長得像蜗顽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子突梦,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容