MachO文件
Mach-O是Mach Object文件格式的縮寫调炬,是mac以及iOS上可執(zhí)行文件的格式。是一種用于可執(zhí)行文件舱馅、目標(biāo)代碼缰泡、動(dòng)態(tài)庫的文件格式。作為a.out格式的替代代嗤,Mach-O提供了更強(qiáng)的擴(kuò)展性棘钞。
類似于windows上的PE格式 (Portable Executable ),linux上的elf格式 (Executable and Linking Format)
Mach-O文件格式
- 目標(biāo)文件.o
- 庫文件
- .a
- .dylib
- framework
- 可執(zhí)行文件
- dyld
- .dsym
實(shí)際開發(fā)中干毅,MatchO文件有很多不同的類型宜猜,可以通過在Xcode上指定。
Targets
→Build Settings
→Linking
→Mach-O Type
通用二進(jìn)制文件
- 蘋果公司提出的一種程序代碼硝逢,能同時(shí)適用多種架構(gòu)的二進(jìn)制文件姨拥。
- 同一個(gè)程序包中同時(shí)為多種架構(gòu)提供最理想的性能绅喉。
- 因?yàn)樾枰獌?chǔ)存多種代碼,通常比單一平臺(tái)二進(jìn)制的程序要大叫乌。
- 由于執(zhí)行中只調(diào)用一部分代碼柴罐,運(yùn)行起來也不需要額外的內(nèi)存。
在Xcode編譯可以指定生成哪些架構(gòu)的Match-O文件憨奸,同時(shí)也可以添加其他架構(gòu)
Targets
→Build Settings
→Architectures
→Architectures
設(shè)備的CPU架構(gòu)(指令集)
- 模擬器:
- 4s-5: i386
- 5s-6s Plus: x86_64
- 真機(jī)(iOS設(shè)備):
- armv6: iPhone革屠、iPhone 2、iPhone 3G排宰、iPod Touch(第一代)似芝、iPod Touch(第二代)
- armv7: iPhone 3Gs、iPhone 4板甘、iPhone 4s国觉、iPad、iPad 2
- armv7s: iPhone 5虾啦、iPhone 5c
- arm64: iPhone 5s之后機(jī)型
Mach-O架構(gòu)拆分、合并
- lipo工具
- 查看MachO架構(gòu)
$lipo -info 'MachO文件'
- 拆分MachO架構(gòu)
$lipo 'MachO文件' –thin '架構(gòu)名' –output '目標(biāo)MachO文件'
- 合并MachO架構(gòu)
$lipo -create '第一個(gè)MachO文件' '第二個(gè)MachO文件 -output '目標(biāo)MachO文件'
- file指令:查看文件信息
$file 文件路徑
MachO文件結(jié)構(gòu)
Mach-O 的組成結(jié)構(gòu)如圖所示痕寓,主要包括三個(gè)部分:Header傲醉、Load commands、Data
Header
包含二進(jìn)制文件的一般信息呻率,架構(gòu)類型硬毕、字節(jié)順序、加載指令的數(shù)量等礼仗。
struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
magic:定位結(jié)構(gòu)是64位還是32位 (e.g. MH_MAGIC_64)
cputype:CPU類型 (e.g. CPU_TYPE_ARM64)
cpusubtype:CPU具體類型 (e.g. CPU_SUBTYPE_ARM64_ALL)
filetype:文件類型 (e.g. MH_EXECUTE)
ncmds:Load Commands條數(shù)
sizeofcmds:Load Commands大小
flags:標(biāo)志位吐咳。標(biāo)識(shí)二進(jìn)制文件支持的功能,主要和系統(tǒng)加載元践、鏈接有關(guān)
reserved:預(yù)留區(qū)(只有64位才有)
Load Commands
包含區(qū)域的位置韭脊、符號(hào)表、動(dòng)態(tài)符號(hào)表等单旁。描述了文件中數(shù)據(jù)的具體組織結(jié)構(gòu)沪羔,不同的數(shù)據(jù)類型使用不同的加載命令表示。
- LC_SEGMENT_64(__PAGEZERO)
- VM Size:虛擬內(nèi)存象浑,大小4G(32位是16M)蔫饰。用于區(qū)分32位及存儲(chǔ)位置
- LC_SEGMENT_64(__TEXT)
- LC_SEGMENT_64(__DATA)
- LC_SEGMENT_64(__LINKEDIT)
- VM Address:虛擬內(nèi)存地址
- VM Size:虛擬內(nèi)存大小
- File Offset:數(shù)據(jù)在文件中的起始位置
- File Size:數(shù)據(jù)在文件中的大小
- LC_DYLD_INFO_ONLY(動(dòng)態(tài)鏈接相關(guān)信息)
- Rebase:進(jìn)行重定向的位置信息。當(dāng)MachO加載到內(nèi)存里愉豺,系統(tǒng)會(huì)隨機(jī)分配一個(gè)內(nèi)存偏移大小aslr篓吁,和rebase里面的offset,對接(位置相加)獲取代碼在內(nèi)存中的實(shí)際位置蚪拦。再根據(jù)size開辟實(shí)際內(nèi)存
- Binding:綁定的位置信息
- Weak Binding:弱綁定的位置信息
- Lazy Binding:懶加載綁定的位置信息
- Export:對外的位置信息
- LC_SYMTAB(符號(hào)表地址)
- Symbol Table Offset:符號(hào)表的位置杖剪。函數(shù)名稱冻押、函數(shù)地址關(guān)聯(lián)的信息
- Number of Symbol:符號(hào)數(shù)
- String Table Offset:符號(hào)名稱位置
- String Table Size:符號(hào)名稱大小
- LC_DYSYMTAB(動(dòng)態(tài)符號(hào)表地址)
- LC_LOAD_DYLINKER(動(dòng)態(tài)庫連接器:dyld)
- Str Offset:動(dòng)態(tài)庫連接器位置
- Name:動(dòng)態(tài)庫連接器路徑(dyld)
- LC_UUID(MachO文件唯一標(biāo)識(shí))
- LC_VERSION_MIN_IPHONESOS(MachO文件支持最低的操作系統(tǒng)版本)
- LC_SOURCE_VERSION(源代碼版本)
- LC_MAIN(MachO程序入口:設(shè)置程序主線程的入口地址和棧大小)
- Entry Offset:入口位置
- Stacksize:堆棧大小
- Entry Point:入口點(diǎn)(內(nèi)存地址)
- LC_ENCRYPTION_INFO_64(加密信息)
- Crypt Offset:加密信息位置
- Crypt Size:加密信息大小
- Crypt ID:加密信息ID摘盆。非加密是0翼雀,加密是1
- LC_LOAD_DYLIB(依賴庫的路徑,包含三方庫)
- Str Offset:動(dòng)態(tài)庫位置
- Time Stamp:動(dòng)態(tài)庫時(shí)間
- Current Version:動(dòng)態(tài)庫版本
- LC_RPATH(frameworks信息)
- LC_FUNCTION_STARTS(函數(shù)的起始位置表)
- LC_DATA_IN_CODE(代碼數(shù)據(jù)信息)
- LC_CODE_SIGNATURE(代碼簽名信息)
Data
由 Segment 段和 Section 節(jié)組成孩擂。存放具體數(shù)據(jù):代碼狼渊、數(shù)據(jù)、字符串常量类垦、類狈邑、方法等。
- Segment 組成
#define SEG_PAGEZERO "__PAGEZERO" /* 當(dāng)時(shí) MH_EXECUTE 文件時(shí)蚤认,捕獲到空指針 */
#define SEG_TEXT "__TEXT" /* 代碼/只讀數(shù)據(jù)段 */
#define SEG_DATA "__DATA" /* 數(shù)據(jù)段 */
#define SEG_OBJC "__OBJC" /* Objective-C runtime 段 */
#define SEG_LINKEDIT "__LINKEDIT" /* 包含需要被動(dòng)態(tài)鏈接器使用的符號(hào)和其他表米苹,包括符號(hào)表、字符串表等 */
- Segment 的數(shù)據(jù)結(jié)構(gòu)
struct segment_command_64 {
uint32_t cmd; /* LC_SEGMENT_64 */
uint32_t cmdsize; /* section_64 結(jié)構(gòu)體所需要的空間 */
char segname[16]; /* segment 名字砰琢,上述宏中的定義 */
uint64_t vmaddr; /* 所描述段的虛擬內(nèi)存地址 */
uint64_t vmsize; /* 為當(dāng)前段分配的虛擬內(nèi)存大小 */
uint64_t fileoff; /* 當(dāng)前段在文件中的偏移量 */
uint64_t filesize; /* 當(dāng)前段在文件中占用的字節(jié) */
vm_prot_t maxprot; /* 段所在頁所需要的最高內(nèi)存保護(hù)蘸嘶,用八進(jìn)制表示 */
vm_prot_t initprot; /* 段所在頁原始內(nèi)存保護(hù) */
uint32_t nsects; /* 段中 Section 數(shù)量 */
uint32_t flags; /* 標(biāo)識(shí)符 */
};
- Section 數(shù)據(jù)結(jié)構(gòu)
部分的 Segment (主要指的 __TEXT 和 __DATA)進(jìn)一步分解為 Section。
struct section_64 {
char sectname[16]; /* Section 名字 */
char segname[16]; /* Section 所在的 Segment 名稱 */
uint64_t addr; /* Section 所在的內(nèi)存地址 */
uint64_t size; /* Section 的大小 */
uint32_t offset; /* Section 所在的文件偏移 */
uint32_t align; /* Section 的內(nèi)存對齊邊界 (2 的次冪) */
uint32_t reloff; /* 重定位信息的文件偏移 */
uint32_t nreloc; /* 重定位條目的數(shù)目 */
uint32_t flags; /* 標(biāo)志屬性 */
uint32_t reserved1; /* 保留字段1 (for offset or index) */
uint32_t reserved2; /* 保留字段2 (for count or sizeof) */
uint32_t reserved3; /* 保留字段3 */
};
以下列舉一些常見的 Section:
__TEXT,__text: 主程序代碼
__TEXT,__stubs / __stub_helper: 用于動(dòng)態(tài)鏈接的樁
__TEXT,__objc_methname: OC方法名稱
__TEXT,__objc_classname: OC類名
__TEXT,__objc_methtype: OC方法類型
__TEXT,__cstring: 程序中c語言字符串
__DATA,__got: 非懶加載符號(hào)表
__DATA,__la_symbol_ptr: 懶加載符號(hào)表
__DATA,__objc_classlist: OC類列表
__DATA,__objc_protollist: OC原型列表
__DATA,__objc_imageinfo: OC鏡像信息
__DATA,__objc_const: OC常量
__DATA,__objc_selfrefs: OC類自引用(self)
__DATA,__objc_superrefs: OC類超類引用(super)
__DATA,__objc_protolrefs: OC原型引用
__DATA,__objc_data / __data: OC代碼數(shù)據(jù)
Dynamic Loader Info: 動(dòng)態(tài)鏈接器所需要使用的信息 (重定向,符號(hào)綁定,懶加載綁定等..)
Function Starts: 方法的起始位置
Symbol Table: 符號(hào)表
Dynamic Symbol Table: 動(dòng)態(tài)符號(hào)表
String Table: 字符串表
Code Signature: 代碼簽名信息