MachO文件
前言
Mach-O(Mach Object):Mach-O 文件是Mach object文件格式的縮寫(xiě)灌砖,它是可執(zhí)行文件璧函、目標(biāo)代碼、動(dòng)態(tài)庫(kù)的文件格式
主要包括:
- 目標(biāo)文件.o
- 庫(kù)文件
- .a
- .dylib
- Framework
- 可執(zhí)行文件
- dyld
- .dsym
可以通過(guò)file命令查看文件類(lèi)型
下面就來(lái)用file簡(jiǎn)單查看下這些文件
-
.o 文件
首先創(chuàng)建一個(gè)C文件通過(guò)Clang編譯可以得到目標(biāo)文件.o
通過(guò) clang -c demo
.命令編譯生成.o目標(biāo)文件
通過(guò)file命令查看.o文件
說(shuō)明.o文件是Mach-O文件類(lèi)型的 64位(64-bit) object文件 x86_64架構(gòu)
使用clang demo.o
生成a.out可執(zhí)行文件
a.out 是一個(gè)可執(zhí)行文件(executable)
- .a 文件 和 Framework
使用find ~/ -name "*.a"
命令可以找到家目錄下的.a文件
找到之后查看一下.a
使用file命令查看.a文件
輸出current ar archive random library這一坨不知道是什么鬼基显,有知道的大神可以幫忙解釋一下
-
.dylib文件
使用file命令查看
4.dyld
dyld 是一個(gè)動(dòng)態(tài)連接器(dynamic linker)蘸吓,包含多個(gè)架構(gòu)的通用二進(jìn)制文件(universal binary with 3 architectures)
通用二進(jìn)制文件
通用二進(jìn)制文件是蘋(píng)果公司提出來(lái)的一種程序代碼,能同時(shí)適用多種架構(gòu)
實(shí)現(xiàn)同一個(gè)程序包為多種架構(gòu)提供最理想的性能
因?yàn)榇嬖卺槍?duì)多種架構(gòu)的代碼所以比單一架構(gòu)的包體積大撩幽,又因?yàn)榇嬖诠餐姆菆?zhí)行資源(代碼以外的)库继,所以比多個(gè)單一平臺(tái)代碼包的體積小
由于每種架構(gòu)只運(yùn)行對(duì)應(yīng)架構(gòu)的代碼,所以運(yùn)行起來(lái)時(shí)不會(huì)占用額外的內(nèi)存
指令集
Armv6窜醉、armv7宪萄、armv7s、arm64都是arm處理器的指令集酱虎,所有指令集原則上都是向下兼容的雨膨,如iPhone4S的CPU默認(rèn)指令集為armv7指令集,但它同時(shí)也兼容armv6指令集读串,只是使用armv6指令集時(shí)無(wú)法充分發(fā)揮其性能聊记,即無(wú)法使用armv7指令集中的新特性,同理恢暖,iPhone5的處理器標(biāo)配armv7s指令集排监,同時(shí)也支持armv7指令集,只是無(wú)法進(jìn)行相關(guān)的性能優(yōu)化杰捂,從而導(dǎo)致程序的執(zhí)行效率沒(méi)那么高舆床。
需要注意的是iOS模擬器沒(méi)有運(yùn)行arm指令集,編譯運(yùn)行的是x86指令集嫁佳,所以挨队,只有在iOS設(shè)備上,才會(huì)執(zhí)行設(shè)備對(duì)應(yīng)的arm指令集蒿往。
移動(dòng)設(shè)備默認(rèn)指令集
- armv6 : iPhone, iPhone2, iPhone3G
- armv7(32bit):iPhone3GS, iPhone4, iPhone4S
- armv7S(32bit):iPhone4/iPhone4s (32位)
- arm64(64bit):iPhone5s(5s+)
- x86_64(64bit): 支持非M1Mac電腦的cpu架構(gòu)(64位模擬器)
- i386:32位架構(gòu)模擬器
iOS11(及以上)系統(tǒng)只支持64位的設(shè)備就是5s(及以上)的設(shè)備才能安裝盛垦,Xcode所以選擇iOS11及以上系統(tǒng)Archive時(shí)生成的包只包含arm64架構(gòu),選擇iOS10及以下系統(tǒng)打出來(lái)的包才有可能包含多個(gè)架構(gòu)
在Xcode -> build Settings->search "mach"可以選擇編譯生成的產(chǎn)物
Mach-O Type
- Executable:可執(zhí)行文件
- Dynamic Library:動(dòng)態(tài)庫(kù)
- Static Library:靜態(tài)庫(kù)
- Bundle:Bundle
- Relocatable Object File:這個(gè)不知道是什么鬼
使用Xcode編譯 選擇最低支撐iOS11.0系統(tǒng)
查看編譯生成包中的可執(zhí)行文件
可以看到編譯生成包中的可執(zhí)行文件只支持arm64架構(gòu)
再次選擇最低支撐iOS10.0系統(tǒng)
可以看到編譯生成包中的可執(zhí)行文件變成了通用二進(jìn)制文件支持arm64瓤漏、和armv7兩種架構(gòu)
Xcode中編譯架構(gòu)設(shè)置 Build Settings -> Search "architectures" 下的Architecture
默認(rèn)最多只支持arm64腾夯、armv7,可以修改這個(gè)配置支持更多架構(gòu)
選擇others加上armv7s然后再build
可以看到可執(zhí)行文件多了armv7s架構(gòu)
Lipo工具
-
使用lipo -info 可以查看MachO文件包含的架構(gòu)
lipo -info MachO名稱(chēng)
-
使用lifo –thin 拆分某種架構(gòu)
lipo MachO文件 –thin 架構(gòu) –output 輸出文件路徑
3.使用lipo -create 合并多種架構(gòu)lipo -create MachO1 MachO2 -output 輸出文件路徑
MachO文件結(jié)構(gòu)
如圖所示MachO文件包含三個(gè)部分:
1. Header
header 是MachO的頭蔬充,其中包含了該MachO文件的一些信息
- 字節(jié)順序蝶俱、架構(gòu)類(lèi)型、加載指令數(shù)量等
- 通過(guò)Header快速確認(rèn)一些信息饥漫,比如32位還是64位榨呆,處理器架構(gòu),文件類(lèi)型等
2. Load commands
Load commands是一張包含一堆加載指令表
- 包含加載指令告訴dyld如何加載這個(gè)MachO
3. Data
Data是MachO中最大的部分
- 包含Segement的具體數(shù)據(jù)
首先用MachOView查看一下Header
在Xcode里command + shift + o 搜索Loader.h可以找到Header的定義
Header的具體內(nèi)容及釋義
使用MachOView
查看MachO文件
其中Load commands各條加載指令的含義如下:
- LC_SEGMENT_64:將文件中(32位或者64位)的段映射到進(jìn)程地址空間中
- LC_DYLD_INFO_ONLY:動(dòng)態(tài)連接相關(guān)信息
- LC_SYMTAB:符號(hào)地址
- LC_DYSYMTAB:動(dòng)態(tài)符號(hào)表地址
- LC_LOAD_DYLINKER:使用什么加載趾浅,iOS的App使用dyld加載
- LC_UUID:文件的UUID
- LC_VERSION_MIN_IPHONEOS:最低支持的操作系統(tǒng)版本
- LC_SOURCE_VERSION:源代碼版本
- LC_MAIN:程序主線(xiàn)程的入口地址和棧大小
- LC_ENCRYPTION_INFO_64 加密信息
- LC_LOAD_DYLIB:依賴(lài)庫(kù)的路徑愕提,包含三方庫(kù)
- LC_RPATH:dyld維護(hù)一個(gè)稱(chēng)為運(yùn)行路徑列表的路徑的當(dāng)前堆棧馒稍。當(dāng)遇到@rpath時(shí)皿哨,它會(huì)被替換為運(yùn)行路徑列表中的每個(gè)路徑浅侨,直到找到可加載的dylib(此項(xiàng)釋義是網(wǎng)上摘錄的還沒(méi)弄懂啥意思)
- LC_FUNCTION_STARTS:函數(shù)起始地址表
- LC_DATA_IN_CODE:定義在代碼段內(nèi)的非指令的表
- LC_CODE_SIGNATURE:代碼簽名
接下來(lái)詳細(xì)看下各個(gè)command的內(nèi)容:
LC_SEGMENT_64
- VM Address:運(yùn)行時(shí)加載到內(nèi)存(虛擬內(nèi)存)的起始地址(要加上ALSR才是真正的內(nèi)存地址)
- VM Size:內(nèi)存中占用大小
- File Offset:在文件中的偏移地址
- File Size:在文件中占用大小
PS:可以看到_TEXT的File Offset是0,所以MachO文件是以代碼段起始的
LC_DYLD_INFO_ONLY
- Rebase Info Offset:重定向開(kāi)始位置的偏移地址
- Rebase Info Size:需要重定向的內(nèi)容的大小
- Binding Info Offset:綁定數(shù)據(jù)的偏移地址
- Binding Info Size:綁定數(shù)據(jù)的大小
- Weak Binding Info Offset:弱綁定
- Weak Binding Info Size:
- Lazy Binding Info Offset:懶綁定(用到的時(shí)候再綁定)
- Lazy Binding Info Size:
- Export Info Offset:對(duì)外開(kāi)放的函數(shù)
- Export Info Size:
LC_SYMTAB符號(hào)相關(guān)(函數(shù)名稱(chēng)证膨,函數(shù)地址)
LC_MAIN 逆向找不到切入點(diǎn)的時(shí)候經(jīng)常用到這個(gè)如输,當(dāng)別人做了防護(hù)App啟動(dòng)就閃退時(shí)可以斷住這個(gè)函數(shù)再做分析
使用 otool
工具可以查看MachO的信息
Load commands的下面就是Data
Data分為_(kāi)TEXT段(代碼段)和_DATA段(數(shù)據(jù)段)
其中Section64(__TEXT,__text)
是主程序代碼
Section64(__TEXT,__stubs)
和Section64(__TEXT,__stub_helper)
是做符號(hào)綁定的
Section64(__TEXT,__objc_methname)
是方法名稱(chēng)
Section64(__TEXT,__objc_classname)
是類(lèi)名稱(chēng)
Section64(__TEXT,__objc_methtype)
是方法類(lèi)型
其他內(nèi)容后面在用到的時(shí)候再補(bǔ)充