Mach-O
Mach-O是Mach object的縮寫,是Mac\iOS上用于存儲(chǔ)程序假褪、庫的標(biāo)準(zhǔn)格式
一個(gè)Mach-O可執(zhí)行文件包含一個(gè)由一組加載命令組成的頭文件。對(duì)于使用共享庫或框架的程序筐带,其中一個(gè)命令指定用于加載程序的鏈接器的位置彪薛。如果你使用Xcode,它總是/usr/lib/dyld坯汤,這是標(biāo)準(zhǔn)的OS X動(dòng)態(tài)鏈接器虐唠。
#define MH_OBJECT 0x1 /* relocatable object file */
#define MH_EXECUTE 0x2 /* demand paged executable file */
#define MH_FVMLIB 0x3 /* fixed VM shared library file */
#define MH_CORE 0x4 /* core file */
#define MH_PRELOAD 0x5 /* preloaded executable file */
#define MH_DYLIB 0x6 /* dynamically bound shared library */
#define MH_DYLINKER 0x7 /* dynamic link editor */
#define MH_BUNDLE 0x8 /* dynamically bound bundle file */
#define MH_DYLIB_STUB 0x9 /* shared library stub for static */
/* linking only, no section contents */
#define MH_DSYM 0xa /* companion file with only debug */
/* sections */
屬于Mach-O格式的文件類型有
可以在xnu源碼中,查看到Mach-O格式的詳細(xì)定義(https://opensource.apple.com/tarballs/xnu/)
EXTERNAL_HEADERS/mach-o/fat.h
EXTERNAL_HEADERS/mach-o/loader.h
1.常見的Mach-O文件類型
MH_OBJECT
**目標(biāo)文件(.o)**
**靜態(tài)庫文件(.a)惰聂,靜態(tài)庫其實(shí)就是N個(gè).o合并在一起**
MH_EXECUTE:可執(zhí)行文件
**.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)信息的文件
**.dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩潰信息)**
2.Mach-O的基本結(jié)構(gòu)
官方描述
https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/MachOTopics/0-Introduction/introduction.html
**一個(gè)Mach-O文件包含3個(gè)主要區(qū)域**
Header
文件類型疆偿、目標(biāo)架構(gòu)類型等
**Load commands**
描述文件在虛擬內(nèi)存中的邏輯結(jié)構(gòu)、布局
**Raw segment data**
在Load commands中定義的Segment的原始數(shù)據(jù)
3.窺探Mach-O的結(jié)構(gòu)
命令行工具
file:查看Mach-O的文件類型
file 文件路徑
otool:查看Mach-O特定部分和段的內(nèi)容
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(https://github.com/gdbinit/MachOView)
4.Universal Binary(通用二進(jìn)制文件
通用二進(jìn)制文件
同時(shí)適用于多種架構(gòu)的二進(jìn)制文件
包含了多種不同架構(gòu)的獨(dú)立的二進(jìn)制文件
因?yàn)樾枰獌?chǔ)存多種架構(gòu)的代碼搓幌,通用二進(jìn)制文件通常比單一平臺(tái)二進(jìn)制的程序要大
由于兩種架構(gòu)有共同的一些資源杆故,所以并不會(huì)達(dá)到單一版本的兩倍之多
由于執(zhí)行過程中,只調(diào)用一部分代碼溉愁,運(yùn)行起來也不需要額外的內(nèi)存
因?yàn)槲募仍瓉淼囊蟠︻酰脖环Q為“胖二進(jìn)制文件”(Fat Binary)
dyld和Mach-O
dyld用于加載以下類型的Mach-O文件
MH_EXECUTE
MH_DYLIB
MH_BUNDLE
APP的可執(zhí)行文件、動(dòng)態(tài)庫都是由dyld負(fù)責(zé)加載的
APP從開發(fā)到安裝到手機(jī)的過程
MJRefreshExample.app中的MJRefreshExample文件是iOS中的可執(zhí)行文件,文件格式是Mach-O
逆向APP的思路
界面分析
Cycript撤蟆、Reveal
代碼分析
對(duì)Mach-O文件的靜態(tài)分析
MachOView奕塑、class-dump、Hopper Disassembler枫疆、ida等
動(dòng)態(tài)調(diào)試
對(duì)運(yùn)行中的APP進(jìn)行代碼調(diào)試
debugserver爵川、LLDB
代碼編寫
注入代碼到APP中
必要時(shí)還可能需要重新簽名、打包ipa
class-dump
顧名思義息楔,它的作用就是把Mach-O文件的class信息給dump出來(把類信息給導(dǎo)出來)寝贡,生成對(duì)應(yīng)的.h頭文件
官方地址:http://stevenygard.com/projects/class-dump/
下載完工具包后將class-dump文件復(fù)制到Mac的/usr/local/bin目錄,這樣在終端就能識(shí)別class-dump命令了
常用格式
class-dump -H Mach-O文件路徑 -o 頭文件存放目錄
-H表示要生成頭文件
-o用于制定頭文件的存放目錄
代碼的編譯過程
動(dòng)態(tài)庫共享緩存(dyld shared cache)
從iOS3.1開始值依,為了提高性能圃泡,絕大部分的系統(tǒng)動(dòng)態(tài)庫文件都打包存放到了一個(gè)緩存文件中(dyld shared cache)
緩存文件路徑:/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armX
dyld_shared_cache_armX的X代表ARM處理器指令集架構(gòu)
v6
iPhone、iPhone3G
iPod Touch愿险、iPod Touch2
v7
iPhone3GS颇蜡、iPhone4、iPhone4S
iPad辆亏、iPad2风秤、iPad3(The New iPad)
iPad mini
iPod Touch3G、iPod Touch4扮叨、iPod Touch5
v7s
iPhone5缤弦、iPhone5C
iPad4
arm64
iPhone5S、iPhone6彻磁、iPhone6 Plus碍沐、iPhone6S、iPhone6S Plus
iPhoneSE衷蜓、iPhone7累提、iPhone7 Plus、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)庫共享緩存一個(gè)非常明顯的好處是節(jié)省內(nèi)存
動(dòng)態(tài)庫的加載
在Mac\iOS中,是使用了/usr/lib/dyld程序來加載動(dòng)態(tài)庫
dyld
dynamic link editor构拳,動(dòng)態(tài)鏈接編輯器
dynamic loader咆爽,動(dòng)態(tài)加載器
dyld源碼
https://opensource.apple.com/tarballs/dyld/
從動(dòng)態(tài)庫共享緩存抽取動(dòng)態(tài)庫
可以使用dyld源碼中的launch-cache/dsc_extractor.cpp
將#if 0前面的代碼刪除(包括#if 0)梁棠,把最后面的#endif也刪掉
編譯dsc_extractor.cpp
clang++ -o dsc_extractor dsc_extractor.cpp
使用dsc_extractor
./dsc_extractor 動(dòng)態(tài)庫共享緩存文件的路徑 用于存放抽取結(jié)果的文件夾
執(zhí)行Mach-O文件
為了執(zhí)行它們的目標(biāo),程序必須執(zhí)行流程并鏈接到動(dòng)態(tài)共享庫斗埂。要使用其他庫或模塊符糊,
應(yīng)用程序必須定義對(duì)這些模塊中的符號(hào)的引用;這些引用在運(yùn)行時(shí)解析。在運(yùn)行時(shí)呛凶,
應(yīng)用程序使用的所有模塊的符號(hào)名稱都位于共享的名稱空間中男娄,類似于目錄。
為了在將來增強(qiáng)應(yīng)用程序及其使用的庫漾稀,應(yīng)用程序和庫開發(fā)人員必須確保為其函數(shù)和數(shù)據(jù)選擇的
名稱與其他模塊中使用的名稱不沖突模闲。
OS X v10.1的兩級(jí)命名空間特性
OS X v10.1引入了兩級(jí)符號(hào)命名空間特性。兩級(jí)名稱空間的第一級(jí)是包含符號(hào)的庫的名稱崭捍,第二級(jí)是符號(hào)的名稱尸折。啟用了兩級(jí)名稱空間特性后,當(dāng)靜態(tài)鏈接器記錄對(duì)導(dǎo)入符號(hào)的引用時(shí)殷蛇,它將記錄對(duì)包含符號(hào)和符號(hào)名稱的庫的名稱的引用实夹。與平面名稱空間相比,使用兩級(jí)名稱空間特性鏈接程序有兩個(gè)好處:
增強(qiáng)了搜索符號(hào)時(shí)的性能粒梦。使用兩級(jí)名稱空間亮航,動(dòng)態(tài)鏈接器知道從哪里開始查找符號(hào)的實(shí)現(xiàn)。使用平面名稱空間匀们,動(dòng)態(tài)鏈接器必須搜索所有加載的庫塞赂,以查找包含符號(hào)的庫。
增強(qiáng)向前兼容性昼蛀。在平面命名空間中,兩個(gè)或多個(gè)庫不能包含具有相同名稱的不同實(shí)現(xiàn)的符號(hào)圆存,因?yàn)閯?dòng)態(tài)鏈接器無法知道哪個(gè)庫包含首選實(shí)現(xiàn)叼旋。這在一開始并不是一個(gè)問題,因?yàn)殪o態(tài)鏈接器會(huì)在您第一次構(gòu)建應(yīng)用程序時(shí)捕獲任何此類問題沦辙。但是夫植,如果某個(gè)依賴共享庫的供應(yīng)商后來發(fā)布了一個(gè)新版本的庫,其中包含與您的程序或另一個(gè)依賴共享庫中的代碼同名的符號(hào)油讯,則程序?qū)o法運(yùn)行详民。
您的應(yīng)用程序必須直接鏈接到包含符號(hào)的共享庫(或者,如果該庫是傘形框架的一部分陌兑,則必須鏈接到包含符號(hào)的傘形框架)沈跨。
在啟用兩級(jí)名稱空間特性的程序中獲取符號(hào)時(shí),必須指定對(duì)包含符號(hào)的共享庫的引用兔综。
默認(rèn)情況下饿凛,OS X v10.1及以后版本中的靜態(tài)鏈接器對(duì)所有Mach-O文件使用兩級(jí)名稱空間狞玛。
這里作為補(bǔ)充引入幾個(gè)問題
1.可執(zhí)行文件與動(dòng)態(tài)庫同為mach-o 的最終產(chǎn)物,它們的關(guān)系是什么
可執(zhí)行文件與動(dòng)態(tài)庫同為mach-o文件涧窒,當(dāng)可執(zhí)行文件里面用到動(dòng)態(tài)庫心肪,就會(huì)在其內(nèi)部保留對(duì)動(dòng)態(tài)庫的引用。
2.動(dòng)態(tài)庫與可執(zhí)行文件作為最終產(chǎn)物纠吴,它為什么比可執(zhí)行文件大
動(dòng)態(tài)庫里面所有的.o都會(huì)被保留硬鞍,因?yàn)樗鼰o法確定哪些符號(hào)會(huì)被外部引用,因此一般的動(dòng)態(tài)庫比可執(zhí)行文件要大
3.靜態(tài)庫也支持two-level namespace嗎戴已?
只有mach-o的文件才支持two-level namespace功能固该。
4.two-level namespace 解決了符號(hào)重復(fù)的問題,但是類名也還是那個(gè)類名恭陡,會(huì)不會(huì)有問題
KVO 的實(shí)現(xiàn)簡(jiǎn)單來說就是創(chuàng)建了一個(gè)NSKVONotifying_A的新類蹬音,繼承被觀察的類A,它替換原有A類的isa 指針休玩,重寫了所提供的keyPath 相關(guān)的setter方法著淆,實(shí)現(xiàn)觀察A類屬性變化。平時(shí)用拴疤,一般不會(huì)有什么問題永部,但是當(dāng)遇上動(dòng)態(tài)庫,情況就不一樣了呐矾。