iOS系統分析(二)Mach-O二進位文件解析

来源:http://www.cnblogs.com/TingyunAPM/archive/2016/11/16/6067520.html
-Advertisement-
Play Games

➠更多技術乾貨請戳:聽雲博客 0x01 Mach-O格式簡單介紹 Mach-O文件格式是 OS X 與 iOS 系統上的可執行文件格式,類似於windows的 PE 文件 與 Linux(其他 Unix like)的 ELF 文件,如果不徹底搞清楚Mach-O的格式與相關內容,那麼深入研究 xnu ...


更多技術乾貨請戳:聽雲博客

0x01  Mach-O格式簡單介紹

Mach-O文件格式是 OS X 與 iOS 系統上的可執行文件格式,類似於windows的 PE 文件 與 Linux(其他 Unix like)的 ELF 文件,如果不徹底搞清楚Mach-O的格式與相關內容,那麼深入研究 xnu 內核就無從談起。

Mach-O文件的格式如下圖所示:

1.png

有如下幾個部分組成:

1. Header:保存了Mach-O的一些基本信息,包括了平臺、文件類型、LoadCommands的個數等等。

2. LoadCommands:這一段緊跟Header,載入Mach-O文件時會使用這裡的數據來確定記憶體的分佈。

3. Data:每一個segment的具體數據都保存在這裡,這裡包含了具體的代碼、數據等等。

0x02 FAT二進位數據 ,數據結構定義在 \<mach-o/fat.h\>

06.png

08.png

1. 第一段為magic 魔數,這裡註意大小端,讀出來之後需要看下是0xCAFEBABE還是 0xBEBAFECA(否則即為thin),需要根據這個來轉後續讀取的位元組的位元組序。  可以看出來 前4byte 為 0xBEBAFECA ,說明為fat。

2. 第二段為arch count,也就是該App或dSYM中包含哪些CPU架構,比如armv7、arm64等,這個例子中為2(後4byte  0x 00 00 00 02),表示包含了兩種cpu架構。  

  `sizeof(struct fat-header) = 8byte`

3. 後續段中包含cputype(0x  0C 00  00 01)、cpusubtype (0x 00 00 00 00)、offset (0x 00 10 00  00)、size(0x 00  F0 27 00)等數據,根據fat中的結構定義,依次讀取,這裡需要說明的是,如果只包含一種CPU架構的話,是沒有這段fat頭定義的,可以跳過這部分,直接讀取Arch數據。

   `sizeof(struct fat-arch) = 20byte`

4. 根據fat頭中讀取的offset數據,我們可以跳到文件對應的arch數據的位置,當然如果只有一種架構的話就不需要計算偏移量了。 下圖給出解析的函數

05.png

0x03 Mach Header二進位數據

通過magic我們可以區分出是32-bit還是64-bit,64-bit多了4個位元組的保留欄位,這裡同樣需要註意位元組序的問題,也就是判斷magic,來確定是否需要轉換位元組序。  

`sizeof(struct mach-header-64) = 32byte`  ; `sizeof(struct mach-header) = 28byte`

07.png

根據mach-header與mach-header_64的定義,很明顯可以看出,Headers的主要作用就是幫助系統迅速的定位Mach-O文件的運行環境,文件類型。

2.png

FileType 

因為Mach-O文件不僅僅用來實現可執行文件,同時還用來實現了其他內容

1. 內核擴展

2. 庫文件

3. CoreDump

4.  其它

3.png

下麵是一些精彩用到的文件類型

1. MH-OBJECT    編譯過程中產生的  obj文件 (gcc -c xxx.c 生成xxx.o文件)

2. MH-EXECUTABLE  可執行二進位文件 (/usr/bin/ls)

3. MH-CORE      CoreDump (崩潰時的Dump文件)

4. MH-DYLIB  動態庫(/usr/lib/裡面的那些共用庫文件)

5. MH-DYLINKER  連接器linker(/usr/lib/dyld文件)

6. MH-KEXT-BUNDLE   內核擴展文件 (自己開發的簡單內核模塊)

flags

Mach-O headers還包含了一些很重要的dyld的載入參數。

4.png

1. MH-NOUNDEFS   目標沒有未定義的符號,不存在鏈接依賴

2. MH-DYLDLINK     該目標文件是dyld的輸入文件,無法被再次的靜態鏈接

3. MH-PIE      允許隨機的地址空間(開啟ASLR  -\>Address Space Layout Randomization)

4. MH-ALLOW-STACK-EXECUTION   棧記憶體可執行代碼,一般是預設關閉的。

5. MH-NO-HEAP-EXECUTION   堆記憶體無法執行代碼

5.png

0x04 LoadCommands

Load Commands 直接就跟在Header後面,所有command占用記憶體的總和在Mach-O Header裡面已經給出了。在載入過Header之後就是通過解析LoadCommand來載入接下來的數據了。定義如下:

6.png

cmd欄位

根據cmd欄位的類型不同,使用了不同的函數來載入。簡單的列出一張表看一看在內核代碼中不同的command類型都有哪些作用。

1. LC-SEGMENT;LC-SEGMENT-64   在內核中由load-segment 函數處理(將segment中的數據載入並映射到進程的記憶體空間去)

2. LC-LOAD-DYLINKER    在內核中由load-dylinker 函數處理(調用/usr/lib/dyld程式)

3. LC-UUID 在內核中由load-uuid 函數處理 (載入128-bit的唯一ID)

4. LC-THREAD  在內核中由load-thread 函數處理 (開啟一個MACH線程,但是不分配棧空間)

5. LC-UNIXTHREAD 在內核中由load-unixthread 函數處理 (開啟一個UNIX posix線程)

6. LC-CODE-SIGNATURE 在內核中由load-code-signature 函數處理 (進行數字簽名)

7. LC-ENCRYPTION-INFO 在內核中由 set-code-unprotect 函數處理 (加密二進位文件)

UUID 二進位數據    128byte

UUID是16個位元組(128bit)的一段數據,是文件的唯一標識,前面提到的符號化時,這個UUID必須要和App二進位文件中的UUID一致,才能被正確的符號化。dwarfdump查看的UUID就是這段數據。讀取這部分數據時通過Command結構讀取的,也就是第一段(0x0000001B)表示接下來的數據類型,第二段(0x00000018)數據的大小(包含Command數據)。 

SymTab 二進位數據

1. 符號表數據塊結構,前二段依然是Command數據。後邊4段分別為符號在文件中的偏移量(0x001DF5E0)、符號個數(0x001DF5E0)、字元串在文件中的偏移量(0x0020C3A0)、字元串表大小(0x000729A8)。 

2. 接下來就是讀取Segment和Section數據塊了,和上面讀取數據塊結構一樣是根據Command結構讀取,下圖展示的Segment數據和Section數據,它們在二進位文件中它們是連續的,也就是每一條Segment數據後面會緊跟著多條對應的Section數據,Section的數據總數是通過Segment結構中的nsects決定的。 

3. 這裡我寫了一個簡單地Mach-O解析工具 [https://github.com/liutianshx2012/Tmacho](https://github.com/liutianshx2012/Tmacho)

09.png

Segment數據

載入數據時,主要載入的就是LC-SEGMET活著LC-SEGMENT_64。其他的Segment的用途在這裡不做深究。

LCSEGMENT以及LC-SEGMENT-64 定義如下圖。

 

7.png

10.png

可以看出,這裡大部分的數據是用來幫助內核將Segment映射到虛擬記憶體的。

nsects 欄位,標示了Segment中有多少secetion ,section是具體有用的數據存放的地方。

TEXT的vmaddr也就是程式的載入地址; —DWARF中表明瞭DWARF數據塊的信息,表示dSYM是DWARF格式的數據結構。 

` sizeof(struct segment-command) = 56byte   ;   sizeof(struct segment-command-64) = 72byte`

Section數據

8.png

從Section數據中,我們可以找到—debug-info、—debug-pubnames, —debug-line等調試信息,通過這些調試信息我們可以找到程式中符號的起始地址、變數類型等信息。如果我們要符號化的話,就可以通過解析這些數據得到我們想要的信息。

Symbol 數據

通過SymTab中的數據可以得到Symbol在文件中的位置和個數,Symbol塊數據中包含了符號的起始地址、字元串的偏移量等數據,這部分數據結構可以參考\<nlist.h\> 和 \<stabl.h\>。在這部分數據全部讀取後,就可以讀取所有的符號數據了,也就是接下來的數據。 

Symbol String 數據

1. 通過SymTab和Symbo中的數據可以得到每個符號字元串在文件中的偏移量和大小,每個符號數據是以0結尾的字元串。 

2. 我們通過以上兩部分數據的組合就可以得到每個symbo在程式中的載入地址了。這些數據對於以後做符號工作都非常的有幫助。

3. 到此,關於dSYM文件中頭部數據讀取就完成了。頭部數據都有相應的數據結構定義,讀取時相對會比較容易些,解析數據時要註意位元組序的問題,32-bit和64-bit數據結構的差異、位元組長度的差異,DWARF版本的差異,每個數據塊之間都是緊密聯繫的,一個位元組的讀取偏差就會造成後續數據的讀取錯誤,正所謂差之毫釐,失之千里。

 

原文鏈接:http://blog.tingyun.com/web/article/detail/1341


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基本演示 背景演示 迴圈演示 回調函數演示 綁定菜單演示 項目導航演示 自動滾動 slide自動滾動 響應式 下載地址 實例代碼 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>fullPage.js ...
  • 現在很多類似以微博發佈動態的效果,下麵為一個用 JavaScript寫的小小的類似微博發佈信息的案例 佈局出來的樣式,點擊藍色的刪除鏈接,會刪除對應的那一行內容 陌陌說:重要知識點:獲取輸入框的數值,創建子節點和給子節點添加內容,刪除對應的節點 ...
  • 模塊系統 Node根據CommonJS規範實現了一套自己的模塊機制,可以使用require()導入一個模塊,使用module.exports導出一個模塊。 require使用 在Node中我們可以使用require()導入一個模塊,此時我們就會獲得一個被導入模塊的對象,我們就可以利用這個對象來完成一 ...
  • startService()和bindService()是開啟服務的兩種方式 ...
  • Android 的系統架構 Android其本質就是在標準的Linux系統上增加了Java虛擬機Dalvik,併在Dalvik虛擬機上搭建了一個JAVA的application framework,所有的應用程式都是基於JAVA的application framework之上。 android分為四 ...
  • HTTP作為一個基礎功能,有必要介紹下在UWP下的使用方法。 一、Get請求: 一般我們用到的是GetAsync方法 上面方法中的前四行和後三行是等價的。 如果要讀取更多的信息,則用GetAsync讀取返回值的response。 二、Post請求: 一般來說,我們最常用的是發送一個json串返回也是 ...
  • 開發環境: macOS 10.12.1 Xcode 8.1 Qt 5.8 gSOAP 2.8 iPhone 6S+iOS 10.1.1 問題: 使用 Qt Quick 寫了一個跨平臺的應用,在Win10、Android、macOS下都已經正常運行,但是連接到 iOS 真機調試的時候,gSOAP 調用 ...
  • 1、什麼是dex? 簡單說就是優化後的android版.exe。每個apk安裝包里都有。相對於PC上的java虛擬機能運行.class;android上的Davlik虛擬機能運行.dex。為何要研究dex格式?因為dex裡面包含了所有app代碼,利用反編譯工具可以獲取java源碼。理解並修改dex文 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...