趣探 Mach-O:檔案格式分析

Martin_wjl發表於2016-09-05

本文所讀的原始碼,可以從這裡找到,這是 Mach-O 系列的第一篇

我們的程式想要跑起來,肯定它的可執行檔案格式要被作業系統所理解,比如 ELFLinux下可執行檔案的格式,PE32/PE32+windows的可執行檔案的格式,那麼對於OS XiOS 來說 Mach-O 是其可執行檔案的格式。

我們平時瞭解到的可執行檔案、庫檔案、Dsym檔案、動態庫、動態聯結器都是這種格式的。Mach-O 的組成結構如下圖所示包括了HeaderLoad commandsData(包含Segement的具體資料)

11852671-9fde036a1ce9d902

Header 的結構

Mach-O的頭部,使得可以快速確認一些資訊,比如當前檔案用於32位還是64位,對應的處理器是什麼、檔案型別是什麼

可以拿下面的程式碼做一個例子

在終端執行以下命令,可以生成一個可執行檔案a.out

我們可以使用MachOView(是一個檢視MachO 格式檔案資訊的開源工具)來檢視
.out檔案的具體格式如何

12852671-542696fbc321ba2c

看到這裡肯定有點懵比,不知道這是什麼東西,下面看一下 header的資料結構

32位結構

64位架構

32位和64位架構的標頭檔案,沒有太大的區別,只是64位多了一個保留欄位罷了

  • magic:魔數,用於快速確認該檔案用於64位還是32位
  • cputype:CPU型別,比如 arm
  • cpusubtype:對應的具體型別,比如arm64、armv7
  • filetype:檔案型別,比如可執行檔案、庫檔案、Dsym檔案,demo中是2 MH_EXECUTE,代表可執行檔案

  • ncmds :載入命令條數
  • sizeofcmds:所有載入命令的大小
  • reserved:保留欄位
  • flags:標誌位,剛才demo中顯示的都在這裡了,其餘的有興趣可以閱讀 mach o原始碼

隨機地址空間

程式每一次啟動,地址空間都會簡單地隨機化。

對於大多數應用程式來說,地址空間隨機化是一個和他們完全不相關的實現細節,但是對於黑客來說,它具有重大的意義。

如果採用傳統的方式,程式的每一次啟動的虛擬記憶體映象都是一致的,黑客很容易採取重寫記憶體的方式來破解程式。採用ASLR可以有效的避免黑客攻擊。

dyld

動態連結器,他是蘋果開源的一個專案,可以在這裡下載,當核心執行LC_DYLINK(後面會說到)時,聯結器會啟動,查詢程式所依賴的動態庫,並載入到記憶體中。

二級名稱空間

這是dyld的一個獨有特性,說是符號空間中還包括所在庫的資訊,這樣子就可以讓兩個不同的庫匯出相同的符號,與其對應的是平坦名稱空間

Load commands 結構

Load commands緊跟在頭部之後,這些載入指令清晰地告訴載入器如何處理二進位制資料,有些命令是由核心處理的,有些是由動態連結器處理的。在原始碼中有明顯的註釋來說明這些是動態聯結器處理的。

這裡列舉幾個看上去比較熟悉的….

load command的結構如下

通過 MachOView來繼續檢視剛才Demo中的Load commands的一些細節,LC_SEGMENT_64LC_SEGMENT是載入的主要命令,它負責指導核心來設定程式的記憶體空間

13852671-dfb91d96fe889dc2
  • cmd:就是就是Load commands的型別,這裡LC_SEGMENT_64代表將檔案中64位的段對映到程式的地址空間。LC_SEGMENT_64LC_SEGMENT的結構差別不大,下面只列舉一個,有興趣可以閱讀原始碼

  • cmdsize:代表load command的大小
  • VM Address :段的虛擬記憶體地址
  • VM Size : 段的虛擬記憶體大小
  • file offset:段在檔案中偏移量
  • file size:段在檔案中的大小

將該段對應的檔案內容載入到記憶體中:從offset處載入 file size大小到虛擬記憶體 vmaddr處,由於這裡在記憶體地址空間中是_PAGEZERO段(這個段不具有訪問許可權,用來處理空指標)所以都是零

還有圖片中的其他段,比如_TEXT對應的就是程式碼段,_DATA對應的是可讀/可寫的資料,_LINKEDIT是支援dyld的,裡面包含一些符號表等資料

  • nsects:標示了Segment中有多少secetion
  • segment name:段的名稱,當前是__PAGEZERO

Segment & Section

這裡有個命名的問題,如下圖所示,__TEXT代表的是Segment,小寫的__text代表 Section

14852671-22f3c34562d029b9

Section的資料結構

  • sectname:比如_textstubs
  • segname :section所屬的segment,比如__TEXT
  • addr :section在記憶體的起始位置
  • size:section的大小
  • offset:section的檔案偏移
  • align :位元組大小對齊
  • reloff :重定位入口的檔案偏移
  • nreloc: 需要重定位的入口數量
  • flags:包含sectiontypeattributes

發現很多底層知識都是以 Mach-O為基礎的,所以最近打算花時間結合Mach-O做一些相對深入的總結,比如符號解析、bitcode、逆向工程等,加油吧

參考連結

相關文章