Mach-O簡介:
Mach-O是Mach object的縮寫,是Mac\iOS上用于存儲程序、庫的標準格式.常見的Mach-O文件比如iOS開發(fā)好的代碼打包好后就是Mach-O格式的文件.
Apple中定義的Mach-O文件包含圖一中幾種:

常見的幾種Mach-O文件:
a、目標文件(.o)
b、靜態(tài)庫文件(.a),靜態(tài)庫其實就是N個.o合并在一起
MH_EXECUTE:可執(zhí)行文件
a、.app/xx
MH_DYLIB:動態(tài)庫文件
a、.dylib
b、.framework/xx
MH_DYLINKER:動態(tài)鏈接編輯器
a、/usr/lib/dyld
MH_DSYM:存儲著二進制文件符號信息的文件
a、.dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩潰信息)
Mach-O的基本結構:
主要包含三個部分:
Header部分:保存了該文件的一些基本信息,如平臺,文件類型,加載命令的個數(shù)等
loadCommends部分:根據這里的數(shù)據來確定內存的分布
Data部分:存放具體的代碼和數(shù)據,data部分是以段來劃分的,loadCommends部分的Segment command對應Data中的Segment

Header:


Header的第一行的file offset為0,Data為4個字節(jié)(2個16進制代表一個字節(jié)),第二行file offset為4,Data為4個字節(jié)
Load Commands:
loadCommand是用于加載指令的,它的大小和數(shù)目在header中已經被提供,在Mach.h下以loadCommand結構體展示

load_commands緊跟mach_header

VM Address:虛擬內存的地址
VM Size:虛擬內存的size,這里轉為16進制為100000000
File Offset:相對于mach-o文件Data數(shù)據的偏移量
File Size:就是數(shù)據大小,就__PAGEZERO有些特殊,F(xiàn)ile Size為0代表實際占用mach-o為0,但是它描述了占用虛擬內存的大小,就是上面的4294967296

VM Address:虛擬內存的地址
VM Size:虛擬內存的size
File Offset:相對于mach-o文件Data數(shù)據的偏移量
File Size:File Size代表實際占用mach-o的大小

Address:該段在文件中的實際地址+adsr
Size:段大小
Offset:該段在文件中的實際地址
segment段類型如下:
1:__PAGEZERO段: 空指針陷阱段,映射到虛擬內存空間的第一頁,用于捕捉對NULL指針的引用;
2: __TEXT 段: 包含了執(zhí)行代碼以及其他只讀數(shù)據。 為了讓內核將它 直接從可執(zhí)行文件映射到共享內存, 靜態(tài)連接器設置該段的虛擬內存權限為不允許寫。當這個段被映射到內存后,可以被所有進程共享。(這主要用在frameworks, bundles和共享庫等程序中,也可以為同一個可執(zhí)行文件的多個進程拷貝使用)
3: __DATA段: 包含了程序數(shù)據,該段可寫;
4: __OBJC段: Objective-C運行時支持庫;
5: __LINKEDIT段: 含有為動態(tài)鏈接庫使用的原始數(shù)據,比如符號,字符串,重定位表條目等等。
每種類型的段又會按不同的功能劃分為幾個區(qū)(section, 名稱小寫,加兩個下橫線作為前綴)如下:
TEXT 段中的section具體類型和作用:
_text:只有可執(zhí)行機器碼(主程序代碼)
_cstring: 去重后的c字符串
_const: 初始化的常量
_stubs: 符號樁,本質上就是一小段會直接跳入到lazybinding的表的對應項指針指向的地址的代碼(???)
_stubs_helper: 輔助函數(shù),上述lazybinding表中沒有找到符號地址都指向這
_unwind_info:用于存儲異常請況信息>
_eh_frame 調試輔助信息
DATA 段中section的具體類型和作用
_data :初始化過得可變的數(shù)據,即全局變量和靜態(tài)變量的存儲是放在一塊的,都放在全局區(qū)(靜態(tài)區(qū)),初始化的全局變量和靜態(tài)變量在一塊區(qū)域
_const: 沒有初始化過得常量
_bss: 沒有初始化的靜態(tài)變量
_common: 沒有初始化過的符號聲明
_mod_init_func : 初始化函數(shù):在main之前調用
_mod_term_func: 終止函數(shù),在main返回之后調用
_nl_symbol_ptr:? 在非lazy-binding的指針表中 的每個表項中的指針都指向一個在裝載過程中,被動態(tài)鏈機器搜索完成的符號(符號的指針)
__la_symbol_ptr:lazy-binding的指針表,每個表項中的指針一開始指向stub_helper(沒有找到的符號指針)
注意: 雖然段類型是不一樣的,但是加載都是使用LC_SEGMENT_64 這個命令, 只是其中加載的段的信息不同

__text: 主程序代碼
__stubs, __stub_helper: 用于動態(tài)鏈接的樁
__cstring: 程序中c語言字符串
__const: 常量
__TEXT,__objc_methname:OC方法名稱
__TEXT__objc_methtype:OC方法類型
__TEXT__objc_classname:OC類名
__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, __bss: 沒有初始化和初始化為0 的全局變量
Dynamic Loader Info:動態(tài)鏈接器所需要使用的信息(重定向,符號綁定,懶加載綁定等..)
后續(xù)的信息就是函數(shù)起始位置,符號表,字符表,代碼簽名等.
查看Mach-O信息:
1.查看Mach-O的文件類型
$ file Mach-O文件路徑
例如查看APP支持的架構(arm64或者32)如圖

2.查看Mach-O的特定部分如圖四(頭信息或者段信息)
$ otool -h Mach-O文件路徑//查看頭信息
$ otool -l Mach-O文件路徑 | grep cryptid//查看Mach-O文件路徑文件是否加密

3.多架構Mach-O文件的處理,可以將arm64和32分開,合并
$ lipo -info 文件路徑//看架構信息
$ lipo 文件路徑 -thin 架構類型 -output 輸出文件路徑//導出某種特定架構
$ lipo 文件路徑1文件路徑2-output 輸出文件路徑//合并多種架構
Mach-o文件詳解:
ASLR:
地址空間布局隨機化,是一種避免app被攻擊的有效保護;進程每次啟動時,地址空間都會被簡單地隨機化——只是偏移,不是攪亂。實現(xiàn)方式是通過內核將Mach-O的段“平移”某個隨機數(shù);
真正的內存地址則是vmaddr?+?ALSR。
http://www.itdecent.cn/p/37f10bb70c50
https://www.exchen.net/mach-o-文件格式解析.html
相關工具:
Mach-OGUI查看工具Mach-OView
MachOView下載編譯即可.