iOS逆向?qū)W習之四(初識Mach-O)

什么是Mach-O文件?

Mach-O是Mach object的縮寫,是Mac\iOS上用來存儲程序、庫的標準格式

Mach-O文件類型

  • 可以點擊下載xnu源碼,在源碼中的<font color=red>EXTERNAL_HEADERS/mach-o/loader.h
    </font>文件中,我們可以看到Mach-O格式的所有文件類型
image

xun是蘋果MacOS\iOS等操作系統(tǒng)的內(nèi)核

  • 常見的Mach-O文件類型
Mach-O類型 示例文件
MH_OBJECT 目標文件(.o)
靜態(tài)庫文件(.a)注:
MH_EXECUTE 可執(zhí)行文件,存放App的所有源碼信息,在.app/xx
MH_DYLIB 動態(tài)庫文件.dylib 或者 .framework/xx
MH_DYLINKER 動態(tài)鏈接編輯器,也就是之前所說的/usr/lib/dyld工具
MH_DSYM 此文件中存儲這二進制文件符號信息,在開發(fā)中,我們經(jīng)常使用此文件來分析App的崩潰信息

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

可以點擊官網(wǎng)查看Mach-O的介紹。

Mach-O組成

Mach-O由3個部分組成

  • Header,包含文件類型、目標架構(gòu)類型等等
  • Load commands,是描述文件在虛擬內(nèi)存中的邏輯結(jié)構(gòu)和布局,相當于一份目錄索引
  • Raw segment data,在Load commands中所定義的Segment,在這里都能找到原始數(shù)據(jù)。

Raw segment data存放了所有的原始數(shù)據(jù),而Load commands相當于Raw segment data的索引目錄

image

窺探Mach-O的結(jié)構(gòu)

常用工具

  • 命令行工具,通過file命令查看Mach-O文件的基本信息
file 文件路徑
  • otool,查看Mach-O特定部分和段的內(nèi)容
#查看Mach-O文件的header信息
otool -h 文件路徑

#查看Mach-O文件的load commands信息
otool -l 文件路徑

更多使用方法,終端輸入otool -help查看

  • lipo,用來處理多架構(gòu)Mach-O文件,常用命令如下
#查看架構(gòu)信息
lipo -info 文件路徑

#導出某種類型的架構(gòu)
lipo 文件路徑 -thin 架構(gòu)類型 -output 輸出文件路徑

#合并多種架構(gòu)類型
lipo 文件路徑1 文件路徑2 -output 輸出文件路徑

Universal Binary(通用二進制文件)

通用二進制文件就是同時適用于多種架構(gòu)的二進制文件,它包含了多種不同架構(gòu)的獨立的二進制文件,它有以下特點

  • 因為需要存儲多種架構(gòu)的代碼,所以通用二進制文件要比單架構(gòu)二進制文件要大
  • 因為兩種種架構(gòu)之間可以共用一些資源,所以兩種架構(gòu)的通用二進制文件大小不會達到單一架構(gòu)版本的兩倍。
  • 運行過程中只會調(diào)用其中的部分代碼,所以運行起來不會占用額外的內(nèi)存
  • 通用二進制文件通常也被稱為“胖二進制文件(Fat binary)”

dyld和Mach-O

dyld是iOS中用來加載可執(zhí)行文件、動態(tài)庫的工具,其實它本身也是一個Mach-O文件。

什么是dyld?
  • dyld 動態(tài)加載器(又叫做動態(tài)鏈接編輯器)
  • dyld的源碼可以點擊此處下載
dyld的作用。

dyld可以用來加載以下三種類型的Mach-O文件

  • MH_EXECUTE
  • MH_DYLIB
  • MH_BUNDLE

通過查看dyld的源碼可以看到加載文件時的類型校驗

image

從編碼到App安裝到手機

想要了解Mach-O文件,首先要了解從編寫代碼,開發(fā)App到App打包并安裝到手機上的整個過程。

  • 首先我們編寫完成代碼之后,會通過LLVM編譯器預(yù)處理我們的代碼,比如將宏放在指定的位置
  • 預(yù)處理結(jié)束之后,LLVM會對代碼進行詞法分析和語法分析,生成AST。AST是抽象語法樹,主要用來進行快速遍歷,實現(xiàn)靜態(tài)代碼檢查的功能。
  • AST會生成IR,IR是一種更加接近機器碼的語言,通過IR可以生成不同平臺的機器碼。對于iOS平臺,IR生成的可執(zhí)行文件就是Mach-O.
  • 然后通過鏈接器將符號和地址綁定在一起,并且將項目中的多個Mach-O文件合并成一個Mach-O文件。
  • 最后通過簽名等操作生成.app文件,然后對.app文件進行壓縮就生成了我們可以安裝的ipa包。
  • 當然,ipa包的安裝途徑有兩種:
    • 通過開發(fā)者賬號上傳到App Store,然后在App Store上下載安裝。
    • 通過PP助手、iFunBox、Xcode等工具來安裝

逆向App,我們需要做哪些工作?

初步了解了什么是Mach-O文件,以及App從開發(fā)到安裝的過程,我們就可以來學習如何逆向一款A(yù)pp

  • 界面分析
    通過之前的學習,我們已經(jīng)可以使用Cycript和Reveal對App的界面進行分析
  • 代碼分析
    iOS開發(fā)中,所有的代碼最后都會經(jīng)過編譯生成Mach-o文件,所以我們需要對Mach-O文件進行靜態(tài)分析

靜態(tài)分析的工具有MachOView、class-dump、Hopper Disassembler、ida等等,后面會一一學習

  • 動態(tài)調(diào)試
    除了靜態(tài)分析,我們還需要運行目標App,對App進行動態(tài)調(diào)試

動態(tài)調(diào)試的工具有debugserver、LLDB等等

  • 代碼編寫、注入
    進行完界面分析、代碼分析和動態(tài)調(diào)試之后,我們可以在特定位置注入我們自己寫的代碼,必要時可以重新簽名并且打包ipa

調(diào)試工具

calss-dump

class-dump的作用就是把Mach-O文件的class信息給導出來,生成對應(yīng)的.h頭文件

  • 可以點擊官網(wǎng)下載class-dump工具包
  • 下載完成之后將其中的class-dump可執(zhí)行文件復制到Mac上的<font color=red>/usr/local/bin</font>目錄中,這樣在終端就能識別class-dump命令了

在Mac中,終端執(zhí)行的所有指令都會去<font color=red>/usr/bin</font>目錄和<font color=red>/usr/local/bin</font>目錄下尋找

  • class-dump的常用命令如下
# -H表示需要生成頭文件  -o用于指定頭文件的存放目錄
class-dump -H Mach-O文件路徑 -o 頭文件存放目錄

Hopper Disassmbler

Hopper Disassmbler可以將Mach-O文件的機器語言反編譯成匯編代碼、OC偽代碼或者是Swift偽代碼。最常使用的快捷鍵有

#找出哪里引用了這個方法
Shift + Option + X

下載地址:https://pan.baidu.com/s/1yP_VcBlQ2G-rWsRue3uSBg


靜態(tài)庫和動態(tài)庫

在iOS開發(fā)中,有很多功能都是現(xiàn)成可用的,不關(guān)你的App在用,其它的App也在用,比如UIKit框架、GUI框架、I/O、網(wǎng)絡(luò)等等。這些庫都是通過鏈接器鏈接到Mach-O文件中的。

靜態(tài)庫

靜態(tài)庫是編譯時鏈接的庫,需要連接進入Mach-O文件中,如果需要更新就必須重新編譯一次,無法做到動態(tài)加載和更新

動態(tài)庫

動態(tài)庫是運行時鏈接的庫。

Mach-O是文件編譯之后的產(chǎn)物,所以動態(tài)庫并沒有參與Mach-O文件的編譯和鏈接。所以Mach-O文件中沒有包含動態(tài)庫的符號定義,也就是說這些符號會直接顯示未定義,但是他們的名字和對應(yīng)庫的路徑會被記錄下來。在運行時通過dlopen和dlsym導入動態(tài)庫時,會根據(jù)記錄的路徑找到對應(yīng)的庫,再通過記錄的名字符號找到綁定的地址。

動態(tài)庫共享緩存(dyld shared cache)

從iOS3.1開始,為了提高性能,絕大部分的系統(tǒng)動態(tài)庫文件都打包存放到了一個緩存文件中(dyld shared cache),緩存路徑是<font color=red>/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armX</font>

dyld_shared_cache_armX里面的X代表ARM處理器指令集的架構(gòu)

ARM指令集

ARM指令集(CPU指令的集合)有以下幾種

ARM指令集 支持的設(shè)備
armv6 iPhone、iPhone3G
iPod Touch、iPod Touch2
armv7 iPhone3GS、iPhone4、iPhone4S
iPad、iPad2、iPad3(The New iPad)、iPad mini
iPod、Touch3G、iPod Touch4、iPod Touch5
armv7s iPhone5、iPhone5C、iPad4
arm64 iPhone5S、iPhone6、iPhone6 Plus、iPhone6S、iPhone6S Plus
iPhoneSE、iPhone7、iPhone7Plus、iPhone8、iPhone8 Plus、iPhoneX
iPad5、iPad Air、iPad Air2、iPad Pro、iPad Pro2
iPad mini with Retina display、iPad mini3、iPad mini4
iPod Touch6

以上所有的指令集都是向下兼容的
為什么要使用動態(tài)庫共享緩存呢?最大的好處就是節(jié)省內(nèi)存。

從動態(tài)庫共享緩存抽取動態(tài)庫

由于動態(tài)庫共享緩存太大,如果想獲取其中某個動態(tài)庫,例如UIKit,就需要從動態(tài)庫共享緩存中抽取對應(yīng)的動態(tài)庫

  • 使用dyld源碼中提供的方式來進行抽取,工具在源碼中的<font color=red>launch-cache/dsc_extractor.cpp</font>文件中

    • 首先需要去掉源碼中的<font color=red>#if 0</font>判斷
    • 然后使用如下命令編譯<font color=red>dsc_extractor.cpp</font>文件
    clang++ -o dsc_extractor dsc_extractor.cpp
    

    此處是將dsc_extractor.cpp編譯生成可執(zhí)行文件dsc_extractor

    • 進入執(zhí)行文件dsc_extractor所在目錄。通過以下的命令來抽取動態(tài)庫
    ./dsc_extractor 動態(tài)庫共享緩存文件的路徑 用于存放抽取結(jié)果的目錄
    
image
>建議抽取armv7s架構(gòu)的動態(tài)庫,arm64抽取時會報以上錯誤,原因是dsc_extractor.bundle不能在Xcode10之后使用

- 抽取完成之后,使用Hopper Disassmbler打開想要逆向的動態(tài)庫,就可以看到動態(tài)庫中的源碼信息。


![image](https://upload-images.jianshu.io/upload_images/20878107-73f56e5bab50be16?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、APP從開發(fā)到安裝到手機的過程 1.1、生成ipa包的過程選擇手機下的可執(zhí)行文件 1.2、真正安裝的過程安裝方...
    IIronMan閱讀 1,944評論 0 4
  • 一、ipa了解是個壓縮包,解壓后 二、逆向app思路; 界面分析Cycript:通過命令行查看界面的組成情況,子控...
    Lovell_閱讀 1,507評論 0 1
  • 逆向App的基本步驟 界面分析Cycript、Reveal 代碼分析對Mach-O文件的靜態(tài)分析MachOView...
    迷心迷閱讀 801評論 0 0
  • Cycript簡介 Cycript是Objective-C++、ES6(JavaScript)、Java等語法的混...
    斑駁的流年無法釋懷閱讀 902評論 0 0
  • 原文鏈接 dyld簡介 共享緩存機制1. dyld_cache_extract提取2. jtool提取3. dsc...
    三三At你閱讀 1,568評論 0 4

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