Mach-O簡(jiǎn)介:
Mach-O是Mach object的縮寫(xiě)惰匙,是Mac\iOS上用于存儲(chǔ)程序跪解、庫(kù)的標(biāo)準(zhǔn)格式.常見(jiàn)的Mach-O文件比如iOS開(kāi)發(fā)好的代碼打包好后就是Mach-O格式的文件.
Apple中定義的Mach-O文件包含圖一中幾種:
常見(jiàn)的幾種Mach-O文件:
a测秸、目標(biāo)文件(.o)
b腿椎、靜態(tài)庫(kù)文件(.a)优烧,靜態(tài)庫(kù)其實(shí)就是N個(gè).o合并在一起
MH_EXECUTE:可執(zhí)行文件
a佃蚜、.app/xx
MH_DYLIB:動(dòng)態(tài)庫(kù)文件
a庸娱、.dylib
b、.framework/xx
MH_DYLINKER:動(dòng)態(tài)鏈接編輯器
a谐算、/usr/lib/dyld
MH_DSYM:存儲(chǔ)著二進(jìn)制文件符號(hào)信息的文件
a熟尉、.dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩潰信息)
Mach-O的基本結(jié)構(gòu):
主要包含三個(gè)部分:
Header部分:保存了該文件的一些基本信息,如平臺(tái),文件類(lèi)型,加載命令的個(gè)數(shù)等
loadCommends部分:根據(jù)這里的數(shù)據(jù)來(lái)確定內(nèi)存的分布
Data部分:存放具體的代碼和數(shù)據(jù),data部分是以段來(lái)劃分的洲脂,loadCommends部分的Segment command對(duì)應(yīng)Data中的Segment
Header:
Header的第一行的file offset為0斤儿,Data為4個(gè)字節(jié)(2個(gè)16進(jìn)制代表一個(gè)字節(jié)),第二行file offset為4恐锦,Data為4個(gè)字節(jié)
Load Commands:
loadCommand是用于加載指令的,它的大小和數(shù)目在header中已經(jīng)被提供,在Mach.h下以loadCommand結(jié)構(gòu)體展示
load_commands緊跟mach_header
VM Address:虛擬內(nèi)存的地址
VM Size:虛擬內(nèi)存的size往果,這里轉(zhuǎn)為16進(jìn)制為100000000
File Offset:相對(duì)于mach-o文件Data數(shù)據(jù)的偏移量
File Size:就是數(shù)據(jù)大小,就__PAGEZERO有些特殊一铅,F(xiàn)ile Size為0代表實(shí)際占用mach-o為0陕贮,但是它描述了占用虛擬內(nèi)存的大小,就是上面的4294967296
VM Address:虛擬內(nèi)存的地址
VM Size:虛擬內(nèi)存的size
File Offset:相對(duì)于mach-o文件Data數(shù)據(jù)的偏移量
File Size:File Size代表實(shí)際占用mach-o的大小
Address:該段在文件中的實(shí)際地址+adsr
Size:段大小
Offset:該段在文件中的實(shí)際地址
segment段類(lèi)型如下:
1:__PAGEZERO段: 空指針陷阱段潘飘,映射到虛擬內(nèi)存空間的第一頁(yè)飘蚯,用于捕捉對(duì)NULL指針的引用馍迄;
2: __TEXT 段: 包含了執(zhí)行代碼以及其他只讀數(shù)據(jù)。 為了讓內(nèi)核將它 直接從可執(zhí)行文件映射到共享內(nèi)存局骤, 靜態(tài)連接器設(shè)置該段的虛擬內(nèi)存權(quán)限為不允許寫(xiě)攀圈。當(dāng)這個(gè)段被映射到內(nèi)存后,可以被所有進(jìn)程共享峦甩。(這主要用在frameworks, bundles和共享庫(kù)等程序中赘来,也可以為同一個(gè)可執(zhí)行文件的多個(gè)進(jìn)程拷貝使用)
3: __DATA段: 包含了程序數(shù)據(jù),該段可寫(xiě)凯傲;
4: __OBJC段: Objective-C運(yùn)行時(shí)支持庫(kù)犬辰;
5: __LINKEDIT段: 含有為動(dòng)態(tài)鏈接庫(kù)使用的原始數(shù)據(jù),比如符號(hào)冰单,字符串幌缝,重定位表?xiàng)l目等等。
每種類(lèi)型的段又會(huì)按不同的功能劃分為幾個(gè)區(qū)(section, 名稱小寫(xiě),加兩個(gè)下橫線作為前綴)如下:
TEXT 段中的section具體類(lèi)型和作用:
_text:只有可執(zhí)行機(jī)器碼(主程序代碼)
_cstring: 去重后的c字符串
_const: 初始化的常量
_stubs: 符號(hào)樁,本質(zhì)上就是一小段會(huì)直接跳入到lazybinding的表的對(duì)應(yīng)項(xiàng)指針指向的地址的代碼(???)
_stubs_helper: 輔助函數(shù),上述lazybinding表中沒(méi)有找到符號(hào)地址都指向這
_unwind_info:用于存儲(chǔ)異常請(qǐng)況信息>
_eh_frame 調(diào)試輔助信息
DATA 段中section的具體類(lèi)型和作用
_data :初始化過(guò)得可變的數(shù)據(jù)诫欠,即全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的涵卵,都放在全局區(qū)(靜態(tài)區(qū)),初始化的全局變量和靜態(tài)變量在一塊區(qū)域
_const: 沒(méi)有初始化過(guò)得常量
_bss: 沒(méi)有初始化的靜態(tài)變量
_common: 沒(méi)有初始化過(guò)的符號(hào)聲明
_mod_init_func : 初始化函數(shù):在main之前調(diào)用
_mod_term_func: 終止函數(shù),在main返回之后調(diào)用
_nl_symbol_ptr:? 在非lazy-binding的指針表中 的每個(gè)表項(xiàng)中的指針都指向一個(gè)在裝載過(guò)程中荒叼,被動(dòng)態(tài)鏈機(jī)器搜索完成的符號(hào)(符號(hào)的指針)
__la_symbol_ptr:lazy-binding的指針表轿偎,每個(gè)表項(xiàng)中的指針一開(kāi)始指向stub_helper(沒(méi)有找到的符號(hào)指針)
注意: 雖然段類(lèi)型是不一樣的,但是加載都是使用LC_SEGMENT_64 這個(gè)命令, 只是其中加載的段的信息不同
__text: 主程序代碼
__stubs, __stub_helper: 用于動(dòng)態(tài)鏈接的樁
__cstring: 程序中c語(yǔ)言字符串
__const: 常量
__TEXT,__objc_methname:OC方法名稱
__TEXT__objc_methtype:OC方法類(lèi)型
__TEXT__objc_classname:OC類(lèi)名
__DATA,__objc_classlist:OC類(lèi)列表
__DATA,__objc_protollist:OC原型列表
__DATA,__objc_imageinfo:OC鏡像信息
__DATA,__objc_const:OC常量
__DATA,__objc_selfrefs:OC類(lèi)自引用(self)
__DATA,__objc_superrefs:OC類(lèi)超類(lèi)引用(super)
__DATA,__objc_protolrefs:OC原型引用
__DATA, __bss: 沒(méi)有初始化和初始化為0 的全局變量
Dynamic Loader Info:動(dòng)態(tài)鏈接器所需要使用的信息(重定向,符號(hào)綁定,懶加載綁定等..)
后續(xù)的信息就是函數(shù)起始位置,符號(hào)表,字符表,代碼簽名等.
查看Mach-O信息:
1.查看Mach-O的文件類(lèi)型
$ file Mach-O文件路徑
例如查看APP支持的架構(gòu)(arm64或者32)如圖
2.查看Mach-O的特定部分如圖四(頭信息或者段信息)
$ otool -h Mach-O文件路徑//查看頭信息
$ otool -l Mach-O文件路徑 | grep cryptid//查看Mach-O文件路徑文件是否加密
3.多架構(gòu)Mach-O文件的處理,可以將arm64和32分開(kāi),合并
$ lipo -info 文件路徑//看架構(gòu)信息
$ lipo 文件路徑 -thin 架構(gòu)類(lèi)型 -output 輸出文件路徑//導(dǎo)出某種特定架構(gòu)
$ lipo 文件路徑1文件路徑2-output 輸出文件路徑//合并多種架構(gòu)
Mach-o文件詳解:
ASLR:
地址空間布局隨機(jī)化,是一種避免app被攻擊的有效保護(hù)被廓;進(jìn)程每次啟動(dòng)時(shí)坏晦,地址空間都會(huì)被簡(jiǎn)單地隨機(jī)化——只是偏移,不是攪亂嫁乘。實(shí)現(xiàn)方式是通過(guò)內(nèi)核將Mach-O的段“平移”某個(gè)隨機(jī)數(shù)昆婿;
真正的內(nèi)存地址則是vmaddr?+?ALSR。
http://www.reibang.com/p/37f10bb70c50
https://www.exchen.net/mach-o-文件格式解析.html
相關(guān)工具:
Mach-OGUI查看工具M(jìn)ach-OView
MachOView下載編譯即可.