什么是Mach-O文件乘寒?
Mach-O是Mach object的縮寫,是Mac\iOS上用來存儲(chǔ)程序匪补、庫的標(biāo)準(zhǔn)格式
Mach-O文件類型
- 可以點(diǎn)擊下載xnu源碼伞辛,在源碼中的<font color=red>EXTERNAL_HEADERS/mach-o/loader.h
</font>文件中,我們可以看到Mach-O格式的所有文件類型
xun是蘋果MacOS\iOS等操作系統(tǒng)的內(nèi)核
- 常見的Mach-O文件類型
Mach-O類型 | 示例文件 |
---|---|
MH_OBJECT | 目標(biāo)文件(.o) 靜態(tài)庫文件(.a)注: |
MH_EXECUTE | 可執(zhí)行文件夯缺,存放App的所有源碼信息蚤氏,在.app/xx |
MH_DYLIB | 動(dòng)態(tài)庫文件.dylib 或者 .framework/xx |
MH_DYLINKER | 動(dòng)態(tài)鏈接編輯器,也就是之前所說的/usr/lib/dyld工具 |
MH_DSYM | 此文件中存儲(chǔ)這二進(jìn)制文件符號(hào)信息踊兜,在開發(fā)中竿滨,我們經(jīng)常使用此文件來分析App的崩潰信息 |
Mach-O的基本結(jié)構(gòu)
可以點(diǎn)擊官網(wǎng)查看Mach-O的介紹。
Mach-O組成
Mach-O由3個(gè)部分組成
- Header捏境,包含文件類型于游、目標(biāo)架構(gòu)類型等等
- Load commands,是描述文件在虛擬內(nèi)存中的邏輯結(jié)構(gòu)和布局,相當(dāng)于一份目錄索引
- Raw segment data,在Load commands中所定義的Segment垫言,在這里都能找到原始數(shù)據(jù)贰剥。
Raw segment data存放了所有的原始數(shù)據(jù),而Load commands相當(dāng)于Raw segment data的索引目錄
窺探Mach-O的結(jié)構(gòu)
常用工具
- 命令行工具筷频,通過file命令查看Mach-O文件的基本信息
file 文件路徑
- otool鸠澈,查看Mach-O特定部分和段的內(nèi)容
#查看Mach-O文件的header信息
otool -h 文件路徑
#查看Mach-O文件的load commands信息
otool -l 文件路徑
更多使用方法,終端輸入otool -help查看
- lipo截驮,用來處理多架構(gòu)Mach-O文件,常用命令如下
#查看架構(gòu)信息
lipo -info 文件路徑
#導(dǎo)出某種類型的架構(gòu)
lipo 文件路徑 -thin 架構(gòu)類型 -output 輸出文件路徑
#合并多種架構(gòu)類型
lipo 文件路徑1 文件路徑2 -output 輸出文件路徑
- GUI工具,MachOView的使用
- 點(diǎn)擊查看MachOView官網(wǎng)
- 直接點(diǎn)擊下載MachOView.dmg,提取碼: 62jk
Universal Binary(通用二進(jìn)制文件)
通用二進(jìn)制文件就是同時(shí)適用于多種架構(gòu)的二進(jìn)制文件际度,它包含了多種不同架構(gòu)的獨(dú)立的二進(jìn)制文件葵袭,它有以下特點(diǎn)
- 因?yàn)樾枰鎯?chǔ)多種架構(gòu)的代碼,所以通用二進(jìn)制文件要比單架構(gòu)二進(jìn)制文件要大
- 因?yàn)閮煞N種架構(gòu)之間可以共用一些資源乖菱,所以兩種架構(gòu)的通用二進(jìn)制文件大小不會(huì)達(dá)到單一架構(gòu)版本的兩倍坡锡。
- 運(yùn)行過程中只會(huì)調(diào)用其中的部分代碼蓬网,所以運(yùn)行起來不會(huì)占用額外的內(nèi)存
- 通用二進(jìn)制文件通常也被稱為“胖二進(jìn)制文件(Fat binary)”
dyld和Mach-O
dyld是iOS中用來加載可執(zhí)行文件、動(dòng)態(tài)庫的工具鹉勒,其實(shí)它本身也是一個(gè)Mach-O文件帆锋。
什么是dyld?
- dyld 動(dòng)態(tài)加載器(又叫做動(dòng)態(tài)鏈接編輯器)
- dyld的源碼可以點(diǎn)擊此處下載
dyld的作用禽额。
dyld可以用來加載以下三種類型的Mach-O文件
- MH_EXECUTE
- MH_DYLIB
- MH_BUNDLE
通過查看dyld的源碼可以看到加載文件時(shí)的類型校驗(yàn)
從編碼到App安裝到手機(jī)
想要了解Mach-O文件锯厢,首先要了解從編寫代碼,開發(fā)App到App打包并安裝到手機(jī)上的整個(gè)過程脯倒。
- 首先我們編寫完成代碼之后实辑,會(huì)通過LLVM編譯器預(yù)處理我們的代碼,比如將宏放在指定的位置
- 預(yù)處理結(jié)束之后藻丢,LLVM會(huì)對代碼進(jìn)行詞法分析和語法分析剪撬,生成AST。AST是抽象語法樹悠反,主要用來進(jìn)行快速遍歷残黑,實(shí)現(xiàn)靜態(tài)代碼檢查的功能。
- AST會(huì)生成IR斋否,IR是一種更加接近機(jī)器碼的語言梨水,通過IR可以生成不同平臺(tái)的機(jī)器碼。對于iOS平臺(tái)如叼,IR生成的可執(zhí)行文件就是Mach-O.
- 然后通過鏈接器將符號(hào)和地址綁定在一起冰木,并且將項(xiàng)目中的多個(gè)Mach-O文件合并成一個(gè)Mach-O文件。
- 最后通過簽名等操作生成.app文件笼恰,然后對.app文件進(jìn)行壓縮就生成了我們可以安裝的ipa包踊沸。
- 當(dāng)然,ipa包的安裝途徑有兩種:
- 通過開發(fā)者賬號(hào)上傳到App Store社证,然后在App Store上下載安裝逼龟。
- 通過PP助手、iFunBox追葡、Xcode等工具來安裝
逆向App腺律,我們需要做哪些工作?
初步了解了什么是Mach-O文件宜肉,以及App從開發(fā)到安裝的過程,我們就可以來學(xué)習(xí)如何逆向一款A(yù)pp
- 界面分析
通過之前的學(xué)習(xí)匀钧,我們已經(jīng)可以使用Cycript和Reveal對App的界面進(jìn)行分析 - 代碼分析
iOS開發(fā)中,所有的代碼最后都會(huì)經(jīng)過編譯生成Mach-o文件谬返,所以我們需要對Mach-O文件進(jìn)行靜態(tài)分析
靜態(tài)分析的工具有MachOView之斯、class-dump、Hopper Disassembler遣铝、ida等等佑刷,后面會(huì)一一學(xué)習(xí)
- 動(dòng)態(tài)調(diào)試
除了靜態(tài)分析莉擒,我們還需要運(yùn)行目標(biāo)App,對App進(jìn)行動(dòng)態(tài)調(diào)試
動(dòng)態(tài)調(diào)試的工具有debugserver瘫絮、LLDB等等
- 代碼編寫涨冀、注入
進(jìn)行完界面分析、代碼分析和動(dòng)態(tài)調(diào)試之后麦萤,我們可以在特定位置注入我們自己寫的代碼鹿鳖,必要時(shí)可以重新簽名并且打包ipa
調(diào)試工具
calss-dump
class-dump的作用就是把Mach-O文件的class信息給導(dǎo)出來,生成對應(yīng)的.h頭文件
- 可以點(diǎn)擊官網(wǎng)下載class-dump工具包
- 下載完成之后將其中的class-dump可執(zhí)行文件復(fù)制到Mac上的<font color=red>/usr/local/bin</font>目錄中频鉴,這樣在終端就能識(shí)別class-dump命令了
在Mac中栓辜,終端執(zhí)行的所有指令都會(huì)去<font color=red>/usr/bin</font>目錄和<font color=red>/usr/local/bin</font>目錄下尋找
- class-dump的常用命令如下
# -H表示需要生成頭文件 -o用于指定頭文件的存放目錄
class-dump -H Mach-O文件路徑 -o 頭文件存放目錄
Hopper Disassmbler
Hopper Disassmbler可以將Mach-O文件的機(jī)器語言反編譯成匯編代碼、OC偽代碼或者是Swift偽代碼垛孔。最常使用的快捷鍵有
#找出哪里引用了這個(gè)方法
Shift + Option + X
下載地址:https://pan.baidu.com/s/1yP_VcBlQ2G-rWsRue3uSBg
靜態(tài)庫和動(dòng)態(tài)庫
在iOS開發(fā)中藕甩,有很多功能都是現(xiàn)成可用的,不關(guān)你的App在用周荐,其它的App也在用狭莱,比如UIKit框架、GUI框架概作、I/O腋妙、網(wǎng)絡(luò)等等。這些庫都是通過鏈接器鏈接到Mach-O文件中的讯榕。
靜態(tài)庫
靜態(tài)庫是編譯時(shí)鏈接的庫骤素,需要連接進(jìn)入Mach-O文件中,如果需要更新就必須重新編譯一次愚屁,無法做到動(dòng)態(tài)加載和更新
動(dòng)態(tài)庫
動(dòng)態(tài)庫是運(yùn)行時(shí)鏈接的庫济竹。
Mach-O是文件編譯之后的產(chǎn)物,所以動(dòng)態(tài)庫并沒有參與Mach-O文件的編譯和鏈接霎槐。所以Mach-O文件中沒有包含動(dòng)態(tài)庫的符號(hào)定義送浊,也就是說這些符號(hào)會(huì)直接顯示未定義,但是他們的名字和對應(yīng)庫的路徑會(huì)被記錄下來丘跌。在運(yùn)行時(shí)通過dlopen和dlsym導(dǎo)入動(dòng)態(tài)庫時(shí)袭景,會(huì)根據(jù)記錄的路徑找到對應(yīng)的庫,再通過記錄的名字符號(hào)找到綁定的地址闭树。
動(dòng)態(tài)庫共享緩存(dyld shared cache)
從iOS3.1開始耸棒,為了提高性能,絕大部分的系統(tǒng)動(dòng)態(tài)庫文件都打包存放到了一個(gè)緩存文件中(dyld shared cache)报辱,緩存路徑是<font color=red>/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armX</font>
dyld_shared_cache_armX里面的X代表ARM處理器指令集的架構(gòu)
ARM指令集
ARM指令集(CPU指令的集合)有以下幾種
ARM指令集 | 支持的設(shè)備 |
---|---|
armv6 | iPhone榆纽、iPhone3G iPod Touch、iPod Touch2 |
armv7 | iPhone3GS、iPhone4奈籽、iPhone4S iPad、iPad2鸵赫、iPad3(The New iPad)衣屏、iPad mini iPod、Touch3G辩棒、iPod Touch4狼忱、iPod Touch5 |
armv7s | iPhone5、iPhone5C一睁、iPad4 |
arm64 | iPhone5S钻弄、iPhone6、iPhone6 Plus者吁、iPhone6S窘俺、iPhone6S Plus iPhoneSE、iPhone7复凳、iPhone7Plus瘤泪、iPhone8、iPhone8 Plus育八、iPhoneX iPad5对途、iPad Air、iPad Air2髓棋、iPad Pro实檀、iPad Pro2 iPad mini with Retina display、iPad mini3按声、iPad mini4 iPod Touch6 |
以上所有的指令集都是向下兼容的
為什么要使用動(dòng)態(tài)庫共享緩存呢膳犹?最大的好處就是節(jié)省內(nèi)存。
從動(dòng)態(tài)庫共享緩存抽取動(dòng)態(tài)庫
由于動(dòng)態(tài)庫共享緩存太大儒喊,如果想獲取其中某個(gè)動(dòng)態(tài)庫镣奋,例如UIKit,就需要從動(dòng)態(tài)庫共享緩存中抽取對應(yīng)的動(dòng)態(tài)庫
-
使用dyld源碼中提供的方式來進(jìn)行抽取怀愧,工具在源碼中的<font color=red>launch-cache/dsc_extractor.cpp</font>文件中
- 首先需要去掉源碼中的<font color=red>#if 0</font>判斷
- 然后使用如下命令編譯<font color=red>dsc_extractor.cpp</font>文件
clang++ -o dsc_extractor dsc_extractor.cpp
此處是將dsc_extractor.cpp編譯生成可執(zhí)行文件dsc_extractor
- 進(jìn)入執(zhí)行文件dsc_extractor所在目錄侨颈。通過以下的命令來抽取動(dòng)態(tài)庫
./dsc_extractor 動(dòng)態(tài)庫共享緩存文件的路徑 用于存放抽取結(jié)果的目錄
>建議抽取armv7s架構(gòu)的動(dòng)態(tài)庫,arm64抽取時(shí)會(huì)報(bào)以上錯(cuò)誤芯义,原因是dsc_extractor.bundle不能在Xcode10之后使用
- 抽取完成之后哈垢,使用Hopper Disassmbler打開想要逆向的動(dòng)態(tài)庫,就可以看到動(dòng)態(tài)庫中的源碼信息扛拨。
