Mach-O
類型的文件
-
Mach-O
是一種文件的格式; 是iOS/Mac OS
上存儲程序以及庫的標準格式Mach Object
-
Mach-O
格式的文件-
EXTERNAL_HEADERS/mach-o/fat.h loader.h
-
#define MH_OBJECT 0x1 /* 目標文件*/
#define MH_EXECUTE 0x2 /* 可執行文件 */
#define MH_FVMLIB 0x3 /* fixed VM shared library file */
#define MH_CORE 0x4 /*核心轉儲文件 */
#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 */
#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */
-
常見的
Mach-O
格式的文件-
MH_OBJECT
目標文件.o
-
.a/ .framework
靜態庫- 靜態庫即多個
.o
文件存放在一起實現特定的功能
- 靜態庫即多個
-
MH_EXECUTE
可執行文件.app/MyApp
.out
-
MH_DYLIB
動態庫.framework/xxx
/dylib
-
MH_DYLINKER
動態鏈接器usr/lib/dyld
-
MH_DSYM
存儲二進制文件符號信息的文件.dYSM/Contents/Resources/DWARF/MyApp
image.png -
-
查看項目
target
的Mach-O
文件的類型-
MH_EXECUTE
類型
image.png -
Mach-O
文件的基本結構
-
Mach-O
包含三個主要區域Header
: 文件類型, 目標架構Load command
: 描述文件在虛擬內存中的邏輯與布局Raw segment date
:Load command
中定義的原始數據
- 使用
otool
查看Mach-O
文件
? otool -h DingTalk
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedface 12 9 0x00 2 79 7860 0x00218085
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedfacf 16777228 0 0x00 2 79 8672 0x00218085
- 使用
file
查看Mach-O
文件
# 該Mach-O文件類型是 executable 只有armv7指令集
? HomeDesign3D China.app file HomeDesign3D\ China
HomeDesign3D China: Mach-O executable arm_v7
# 該Mach-O文件 類型是 executable; 有armv7, arm64指令集是一個通用二進制文件
? DingTalk.app file DingTalk
DingTalk: Mach-O universal binary with 2 architectures: [arm_v7: Mach-O executable arm_v7] [arm64]
DingTalk (for architecture armv7): Mach-O executable arm_v7
DingTalk (for architecture arm64): Mach-O 64-bit executable arm64
-
通用二進制文件
universal binary
或者Fat binary
含有多個不同架構的獨立二進制文件; 故體積較大
執行時, 只會選擇一種架構的二進制文件
image.png -
使用
MachOView
查看Mach-O
文件- 以查看
DingTalk
為例
- 以查看
-
RAW
與RVA
RV
: 虛擬地址RAW
: 文件偏移地址(物理地址)RVA
: 相對虛擬地址的偏移
Mach-O
結構詳解
-
以分析
DingTalk
arm64指令集
為例子
Mach Header(arm64)
-
Magic Number
: 魔數, 表示支持設備的CPU位數
oxFEEDFACE
: 表示32位二進制oxFEEDFACF
: 表示64位二進制
cputype
和cpusubtype
:CPU
類型和子類型filetype
:Mach-O
文件類型ncmds
和sizeofcmds
: 用于加載器的加載命令
的條數和大小flags
: 動態鏈接器dyld
的標志
LC_SEGMENT / LC_SEGMENT_64
段的詳解
-
常見段
__PAGEZERO
: 空指針陷阱段_TEXT
: 程序代碼段__DATA
: 程序數據段__RODATA
:read only
程序只讀數據段__LINKEDIT
: 鏈接器使用段
-
section段
常見字段Segment Name
: 該Segment
的名稱, 用于load_segment
VM Address
: 該段的虛擬物理地址VM Size
: 該段所需要分配的虛擬內存大小(字節)File Offset
: 該段在文件中的偏移量File Size
: 該段在文件中占據的字節數-
Maximum VM Protection
: 段的頁面所需要的最高內存保護ox1
: x 執行ox2
: w 寫0x4
: r 讀
Initial VM Protection
: 段頁面初始化的內存保護Number of Sections
: 段中section
區的數量Flags
: 其他標志位
tips: 小結:
根據
LC_SEGMENT
命令 設置進程虛擬內存對于每一個段, 將其內容從
Mach-O
文件加載到內存中即從
Mach-O
文件中的偏移量為File Offset
處加載File Size
字節內容到虛擬內存地址VM Address
處VM Size
字節空間內
段中區section
詳解
-
常見區
section
__text
: 主程序代碼__stubs, __stub_helper
: 用于動態鏈接的樁__cstring
: 程序中c語言
字符串__const
: 常量__RODATA,__objc_methname
:OC
方法名稱__RODATA,__objc_methntype
:OC
方法類型__RODATA,__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 的全局變量
Load Commmands
加載命令中其他信息
-
LC_MAIN
- 設置程序主線程
入口地址
和棧大小
- 設置程序主線程
-
LC_CODE_SIGNATURE
包含
Mach-O
文件的代碼簽名沒有簽名
或簽名不正確
, 該進程會被kill
, 程序崩潰
Mach-O
中動態庫的加載
-
動態庫來源
系統提供的動態庫
第三方動態庫
-
如圖:
DingTalk
使用大量的系統動態庫即
Mach-O
鏡像中有很多對外部庫以及符號
的引用這些引用將在程序啟動時, 由
動態鏈接器 /usr/lib/dyld
來執行符號綁定
-
加載動態鏈接器
-
LC_LOAD_DYLINKER
: 內核執行該命令時, 啟動dyld
-
-
獲取符號表
LC_SYMTAB
: 符號地址表LC_DYSYMTAB
: 動態符號地址表
-
加載動態庫
LC_LOAD_WEAK_DYLIB
LC_LOAD_DYLIB
動態庫加載流程小結
1.0 首先啟動
dyld動態鏈接器
; 內核根據LC_LOAD_DYLINKER
啟動/usr/lib/dyld
2.0 如果
Mach-O
文件中使用了外部定義的符號或函數
, 則會在文本段__TEXT
有__stubs, __stub_helper
區; 區內放著本地未被定義的符號; 編譯器在編譯源碼時會創建對這些未定義符號樁區的調用3.0
dyld
運行時, 會在符號樁區調用地址上; 添加JMP 到 真實函數地址
的指令4.0 至于
dyld
怎么找到指定的動態庫中指定的函數地址? 此時dyld
將加載Load Command
中的LC_LOAD_DYLIB
命令5.0
LC_LOAD_DYLIB(動態庫)
,dyld
將加載每一個指定的庫且搜尋匹配的符號6.0 當符號匹配時, 將在符號表(由
dyld
加載LC_SYMTAB
,LC_DYSYMTAB
獲取)查找對應的函數/符號地址