MachO 文件結構詳解

概念——什麼是MachO?

 蘋果開發者對它必定不陌生,特別是喜歡逆向的同窗,對它的研究更是必不可少。在可安裝的每個.app包中,都有一個與app同名的可執行文件,它可能長這樣:(若是你碰到顯示爲白色的MachO文件,說明當前用戶對其沒有可執行權限bash

 MachO實際上是Mach Object的縮寫,是在Mac以及iOS上可執行的一種文件格式,包括但不限於:可執行文件(.out .o)、動態庫、靜態庫、dyld、目標文件,官方文檔中列舉以下:
它相似於Windows上的PE、Linux上的ELF格式,咱們用file命令看上圖中 AlipayWallet 的文件類型信息:
能夠看到,該示例的MachO文件屬於通用二進制文件(蘋果提出的一種能同時適用多種架構二進制文件的程序代碼),並支持在兩種架構上運行:arm_v7和arm64,包含了多種架構的MachO文件能夠經過lipo thin命令進行拆分: lipo AlipayWallet -thin armv7 -output alipayArmv7,一樣也能用lipo create進行合併: lipo alipayArm64 alipayArmv7 -create -output AlipayWalletNew,你們能夠本身實踐一下。

構造——MachO的內部結構是怎樣的?

一:簡單的講,它包括如下四個組成部分:

  • Header (頭部)
    • 用於快速確認該文件的CPU類型、文件類型等信息
  • LoadCommands (加載命令)
    • 用於告訴loader如何設置並加載二進制數據
  • Data (數據段 segment)
    • 存放數據:代碼、字符常量、類、方法等
    • 能夠擁有多個segment,每一個segment能夠有零到多個section。每一個段都有一段虛擬地址映射到進程的地址空間
  • Loader Info (連接信息)
    • 一個完整的用戶級MachO文件的末端是一系列連接信息。其中包含了動態加載器用來連接可執行文件或者依賴所需使用的符號表、字符串表等

 來用MachOView驗證一下該示例的MachO文件結構: 數據結構

二:逐一探索:

1.Header

 除了用MachOView能查看MachO文件信息,還能夠經過otool命令查看,咱們先來分析Header中的內容:otool -h AlipayWallet架構

  • magic:MachO文件的魔數,用來肯定其屬於64位(0xfeedfacf)仍是32位(0xfeedface)例子中有兩個Header,分別對應的是armv7和arm64的Header,前者32位,後者64位。
  • cputype和cupsubtype表明的是cpu的類型和其子類型,例子中分別是12(c)與九、16777228(100000c)與0定義以下:
#define CPU_TYPE_ARM((cpu_type_t) 12)
#define CPU_SUBTYPE_ARM_V7((cpu_subtype_t) 9)
#define CPU_TYPE_ARM64((cpu_type_t) 16777228)
#define CPU_SUBTYPE_AR64M_ALL((cpu_subtype_t) 0)
複製代碼
  • 接着是filetype,2,表明可執行的文件:
#define MH_EXECUTE 0x2 /* demand paged executable file */
複製代碼
  • ncmds 指的是加載命令(load commands)的數量,例子中一共75個,編號0-74
  • sizeofcmds 表示75個load commands的總字節大小, load commands區域是緊接着header區域的
  • 最後個flags 標識二進制文件支持的功能,主要與系統的加載、連接有關。

這裏爲你準備了 mach_header 的蘋果官方文檔說明:(更多詳細定義請參考loader.happ

2.LoadCommands

咱們繼續用命令查看:otool -l alipayArm64,該示例共有75個加載指令,咱們只截取一個做爲表明,分別爲出如今segment和section中的每個參數進行註釋:函數

Load command 1
      cmd LC_SEGMENT_64         // cmd 是load command的類型,LC_SEGMENT_64的含義是將這個64位的段映射到進程地址空間,即加載命令                      
  cmdsize 712                   // 表明load command的大小
  segname __TEXT                // 16字節的段名字 __TEXT
   vmaddr 0x0000000100000000    // 段的虛擬內存起始地址
   vmsize 0x00000000036a4000    // 段的虛擬內存大小
  fileoff 0                     // 段在文件中的偏移量
 filesize 57294848              // 段在文件中的大小
  maxprot 0x00000005            // 段頁面所須要的最高內存保護(4=r,2=w,1=x)
 initprot 0x00000005            // 段頁面初始的內存保護
   nsects 8                     // 段中包含section的數量
    flags 0x0                   // 其餘雜項標誌位
Section
  sectname __text               // 第一個是__text ,就是主程序代碼
   segname __TEXT               // 該section所屬的 segment名,第一個是__TEXT
      addr 0x0000000100006110   // 該section在內存的啓始位置,0x100006110
      size 0x000000000358a268   // size 該section的大小,0x358a268
    offset 24848                // 24848 0x6110
     align 2^4 (16)             // 字節大小對齊,16
    reloff 0                    // 重定位入口的文件偏移 0
    nreloc 0                    // 須要重定位的入口數量 0
     flags 0x80000400           // 包含section的type和attributes
 reserved1 0                    // ...保留用
 reserved2 0                    // ...保留用
複製代碼

註釋完畢,我又爲你準備了 segment和section 的蘋果官方文檔說明:(更多詳細定義請參考loader.hpost

 我總結了最多見的加載命令以下:

  • LC_SEGMENT_64: 將該段(64位)映射到進程地址空間中
  • LC_DYLD_INFO_ONLY:加載動態連接庫信息(重定向地址、弱引用綁定、懶加載綁定、開放函數等的偏移值等信息)
  • LC_SYMTAB:載入符號表地址
  • LC_DYSYMTAB:載入動態符號表地址
  • LC_LOAD_DYLINKER:加載動態加載庫,能夠看出示例使用的是/usr/lib/dyld
  • LC_UUID:肯定文件的惟一標識,crash解析中也會有這個,去檢測dysm文件和crash文件是否匹配
  • LC_VERSION_MIN_MACOSX/LC_VERSION_MIN_IPHONEOS:肯定二進制文件要求的最低操做系統版本
  • LC_SOURCE_VERSION:構建該二進制文件使用的源代碼版本
  • LC_MAIN:設置程序主線程的入口地址和棧大小
  • LC_ENCRYPTION_INFO_64:獲取加密信息
  • LC_LOAD_DYLIB:加載額外的動態庫
  • LC_FUNCTION_STARTS:定義一個函數起始地址表,使調試器和其餘程序易於看到一個地址是否在函數內
  • LC_DATA_IN_CODE:定義在代碼段內的非指令的表
  • LC_CODE_SIGNATURE:獲取應用簽名信息

3.Data、連接信息

 若是說前面兩部分的主要做用,是讓kern內核知道如何讀取MachO文件,並指定MachO文件的動態連接器(dyly)用來完成後續的動態庫加載,而後設置好程序入口等一些列程序啓動前的信息,那麼Data和連接信息部分,就至關於當程序運行起來後,爲每個映射到虛擬內存中的指令操做提供真實的物理地址支持。詳細的過程會面會單獨寫一篇文章展開來說。學習

收穫——熟悉MachO能夠作什麼

 理解原理很重要,瞭解MachO格式的結構和加載運行,不只能夠幫助咱們理解MacOS和iOS的app可執行文件啓動過程,還能作且不限於:優化

  • bitcode分析
  • crash符號化
  • 符號模塊查找
  • 非OC函數switch
  • 包支持架構分析
  • 常量字符串分析
  • 進程啓動速度優化
  • 學習經典的數據結構

但願你有所收穫!下篇咱們主要圍繞dyld講動態加載過程,see you~ui


參考文章:加密

相關文章
相關標籤/搜索