iOS【Mach-O可執(zhí)行文件】

摘錄:其字德安「Mach-O文件結(jié)構(gòu)」
(以此記錄一下)

iOS上的可執(zhí)行文件相當(dāng)于windows上的.exe可執(zhí)行文件。
在iOS上,主要的可執(zhí)行文件格式是Mach-O格式。

iOS程序包是.ipa文件。解壓縮后里面會有一個payload文件夾,文件夾里有一個.app文件,右鍵顯示包內(nèi)容,然后找到一個一般體積最大跟.app同名的文件,那個文件就是可執(zhí)行文件。

Mach-O類型的文件

  • Mach-O是一種文件的格式; 是iOS/Mac OS上存儲程序以及庫的標(biāo)準(zhǔn)格式

    • Mach Object
  • Mach-O格式的文件

#define MH_OBJECT   0x1     /* 目標(biāo)文件*/
#define MH_EXECUTE  0x2     /* 可執(zhí)行文件 */
#define MH_FVMLIB   0x3     /* fixed VM shared library file */
#define MH_CORE     0x4     /*核心轉(zhuǎn)儲文件 */
#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格式的文件

1、`MH_OBJECT` 目標(biāo)文件
    *`.o`
    *`.a/ .framework`靜態(tài)庫
        *靜態(tài)庫即多個`.o`文件存放在一起實(shí)現(xiàn)特定的功能

2、`MH_EXECUTE` 可執(zhí)行文件
    *`.app/MyApp`
    *`.out`

3、  `MH_DYLIB` 動態(tài)庫
    *`.framework/xxx`
    *`/dylib`

4、`MH_DYLINKER` 動態(tài)鏈接器
    *`usr/lib/dyld`

5、`MH_DSYM` 存儲二進(jìn)制文件符號信息的文件
    *`.dYSM/Contents/Resources/DWARF/MyApp`

如圖:


image

查看項(xiàng)目targetMach-O文件的類型
MH_EXECUTE類型
如圖:

image

Mach-O文件的基本結(jié)構(gòu)

Mach-O包含三個主要區(qū)域

1、`Header`: 文件類型, 目標(biāo)架構(gòu)
2、`Load command`: 描述文件在虛擬內(nèi)存中的邏輯與布局
3、`Raw segment date`: `Load command`中定義的原始數(shù)據(jù)
image
  • 使用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指令集是一個通用二進(jìn)制文件
?  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

  • 通用二進(jìn)制文件

    • universal binary或者Fat binary

    • 含有多個不同架構(gòu)的獨(dú)立二進(jìn)制文件; 故體積較大

    • 執(zhí)行時, 只會選擇一種架構(gòu)的二進(jìn)制文件

    image
  • 使用MachOView查看Mach-O文件

    • 以查看DingTalk為例
image
image
image
  • RAWRVA
    RV: 虛擬地址
    RAW: 文件偏移地址(物理地址)
    RVA: 相對虛擬地址的偏移

Mach-O結(jié)構(gòu)詳解

Mach Header(arm64)
  • Magic Number : 魔數(shù), 表示支持設(shè)備的CPU位數(shù)

    • oxFEEDFACE : 表示32位二進(jìn)制

    • oxFEEDFACF : 表示64位二進(jìn)制

  • cputypecpusubtype: CPU類型和子類型

  • filetype : Mach-O文件類型

  • ncmdssizeofcmds: 用于加載器的 加載命令的條數(shù)和大小

  • flags : 動態(tài)鏈接器dyld的標(biāo)志

image

LC_SEGMENT / LC_SEGMENT_64段的詳解

  • 常見段

    __PAGEZERO: 空指針陷阱段
    _TEXT: 程序代碼段
    __DATA: 程序數(shù)據(jù)段
    __RODATA: read only程序只讀數(shù)據(jù)段
    __LINKEDIT: 鏈接器使用段

image
  • section段常見字段

    Segment Name: 該Segment的名稱, 用于load_segment
    VM Address: 該段的虛擬物理地址
    VM Size: 該段所需要分配的虛擬內(nèi)存大小(字節(jié))
    File Offset: 該段在文件中的偏移量
    File Size: 該段在文件中占據(jù)的字節(jié)數(shù)
    Maximum VM Protection: 段的頁面所需要的最高內(nèi)存保護(hù)

    ox1: x 執(zhí)行
    ox2: w 寫
    0x4: r 讀

    Initial VM Protection: 段頁面初始化的內(nèi)存保護(hù)
    Number of Sections: 段中section區(qū)的數(shù)量
    Flags: 其他標(biāo)志位

段中區(qū)section詳解

  • 常見區(qū)section

    __text: 主程序代碼
    __stubs, __stub_helper: 用于動態(tài)鏈接的樁
    __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 的全局變量

image

Load Commmands加載命令中其他信息

  • 加載動態(tài)鏈接器
    LC_LOAD_DYLINKER: 內(nèi)核執(zhí)行該命令時, 啟動dyld

  • 獲取符號表
    LC_SYMTAB: 符號地址表
    LC_DYSYMTAB: 動態(tài)符號地址表

  • 加載動態(tài)庫
    LC_LOAD_WEAK_DYLIB
    LC_LOAD_DYLIB

動態(tài)庫加載流程小結(jié)
1.0 首先啟動dyld動態(tài)鏈接器; 內(nèi)核根據(jù)LC_LOAD_DYLINKER啟動/usr/lib/dyld

2.0 如果Mach-O文件中使用了外部定義的符號或函數(shù), 則會在文本段__TEXT有__stubs, __stub_helper區(qū); 區(qū)內(nèi)放著本地未被定義的符號; 編譯器在編譯源碼時會創(chuàng)建對這些未定義符號樁區(qū)的調(diào)用

3.0 dyld運(yùn)行時, 會在符號樁區(qū)調(diào)用地址上; 添加JMP 到 真實(shí)函數(shù)地址的指令

4.0 至于dyld怎么找到指定的動態(tài)庫中指定的函數(shù)地址? 此時dyld將加載Load Command中的LC_LOAD_DYLIB命令

5.0 LC_LOAD_DYLIB(動態(tài)庫), dyld將加載每一個指定的庫且搜尋匹配的符號

6.0 當(dāng)符號匹配時, 將在符號表(由dyld加載LC_SYMTAB, LC_DYSYMTAB獲取)查找對應(yīng)的函數(shù)/符號地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容