iOS逆向 MachO文件

歡迎閱讀iOS逆向系列(按序閱讀食用效果更加)緩存

寫在前面

以前在iOS逆向系列中屢次提到MachO,本文將帶着你們一探究竟bash

工具:MachOView 密碼:y2wr微信

1、MachO初探

1.定義

MachO實際上是Mach Object文件格式的縮寫,是mac以及iOS上可執行文件的格式,相似於Windows上的PE格式(Portable Executable)、Linux上的elf格式(Executable and Linking Format)架構

它是一種用於可執行文件、目標代碼、動態庫的文件格式,做爲.out格式的替代,MachO提供了更強的擴展性app

2.常見的MachO文件

  • 目標文件.o
  • 庫文件
    • .a
    • .dylib
    • .Framework
  • 可執行文件
  • dyld(動態連接器)
  • .dsym(符號表:Relese環境運行生成)

3.查看文件類型

$ file xxx.xx 函數

2、關於架構

1.架構表

其實iPhone不一樣的型號對應的架構是不同的工具

架構 手機型號
i386 32位模擬器
x86_64 64位模擬器
armv7 iPhone四、iPhone4S
armv7s iPhone五、iPhone5C
arm64 iPhone5s——iPhoneX
arm64e iPhone XS、iPhone XS Max、iPhoneXR、iPhone11...

2.生成多種架構

新建一個工程,真機運行,查看可執行文件僅僅是一個arm64架構的 post

將項目最低適配系統調爲iOS9.0,真機運行 Relese環境

爲何要改成iOS9.0呢?是由於iPhone5c等armv七、armv7s架構不支持iOS11.0性能

爲何要Relese環境運行呢?由於Xcode默認Debug只生成單一架構 ui

怎麼生成全部架構?Xcode10中只包含了v7和64,須要在Architectures中添加

3、通用二進制文件

1.定義

通用二進制文件(Universal binary)也被叫作胖二進制(Fat binary)

  • 蘋果公司提出的一種程序代碼,能同時適用多種架構的二進制文件
  • 同一個程序包中同時爲多種架構提供最理想的性能
  • 由於須要儲存多種代碼,通用二進制應用程序一般比單一平臺二進制的程序要大
  • 可是因爲兩種架構有共通的非執行資源,因此並不會達到單一版本的兩倍之多
  • 並且因爲執行中只調用一部分代碼,運行起來也不須要額外的內存

2.拆分/合併架構

架構拆分

合併架構

通用二進制大小爲342kb,四個架構大小爲80+80+80+81=321kb

What!爲何不是單純的1+1=2?

由於不一樣架構之間代碼部分是不共用的 (由於代碼的二進制文件不一樣的組合在不一樣的 cpu 上可能會是不一樣的意義),而公共資源文件是公用的

利用上述方法能夠給咱們的app瘦身

結論:

胖二進制拆分後再重組會獲得原始胖二進制

通用二進制的大小可能大於子架構大小之和,也可能小於,也可能等於,取決於公共資源文件的多少

3.終端命令行

// 查看二進制文件
$ lipo -info xx 
// 通用二進制文件
// 拆分二進制文件
lipo xxx -thin armv7 -output xxx
// 組合二進制文件
lipo -create x1 x2 x3 x4 -output xxx
複製代碼

4、MachO文件

1.總體結構

MachOView打開會看到通用二進制文件Fat Header四個可執行文件組成

可執行文件是由 HeaderLoad commandsData組成
咱們能夠這麼理解,把 通用二進制文件看做四本翻譯語言不一樣的書,每本書有 標題(header)目錄(load commands)內容(data)

  • header:
  • load commands:
  • data:

另外咱們也能夠經過otool命令行查看MachO文件結構

$ otool -f universe
複製代碼

2.header

header包含了該二進制文件的字節順序、架構類型、加載指令的數量等,使得能夠快速確認一些信息,好比當前文件用於32 位仍是64 位,對應的處理器是什麼、文件類型是什麼

Xcode中 shift+command+O->load.h->以下信息

struct mach_header_64 {
    uint32_t	magic;		/* 魔數,快速定位64位/32位 */
    cpu_type_t	cputype;	/* cpu 類型 好比 ARM */
    cpu_subtype_t	cpusubtype;	/* cpu 具體類型 好比arm64 , armv7 */
    uint32_t	filetype;	/* 文件類型 例如可執行文件 .. */
    uint32_t	ncmds;		/* load commands 加載命令條數 */
    uint32_t	sizeofcmds;	/* load commands 加載命令大小*/
    uint32_t	flags;		/* 標誌位標識二進制文件支持的功能 , 主要是和系統加載、連接有關*/
    uint32_t	reserved;	/* reserved , 保留字段 */
};
複製代碼

mach_header_64(64位)對比mach_header(32位)只多了一個保留字段

3.load commands

load commands是一張包括區域的位置、符號表、動態符號表等內容的表。 它詳細保存着加載指令的內容,告訴連接器如何去加載這個 Mach-O 文件。 經過查看內存地址咱們發現,在內存中load commands是緊跟在header以後的

名稱 內容
LC_SEGMENT_64 將文件中(32位或64位)的段映射到進程地址空間中
LC_DYLD_INFO_ONLY 動態連接相關信息
LC_SYMTAB 符號地址
LC_DYSYMTAB 動態連接相關信息
LC_LOAD_DYLINKER 動態連接相關信息
LC_UUID 動態連接相關信息
LC_VERSION_MIN_MACOSX 支持最低的操做系統版本
LC_SOURCE_VERSION 源代碼版本
LC_MAIN 設置程序主線程的入口地址和棧大小
LC_LOAD_DYLIB 依賴庫的路徑,包含三方庫
LC_FUNCTION_STARTS 函數起始地址表
LC_CODE_SIGNATURE 代碼簽名

4.data

data是MachO文件中最大的部分,其中_TEXT段_DATA段能給到不少信息

load commandsdata之間還留有很多空間,給咱們留下了注入代碼的衝破口

_TEXT段

名稱 做用
_text 主程序代碼
_stubs、_stub_helper 動態連接
_objc_methodname 方法名稱
_objc_classname 類名稱
_objc_methtype 方法類型(v@:)
_cstring 靜態字符串常量

_DATA段

名稱 做用
_got=>Non-Lazy Symbol Pointers 非懶加載符號表
_la_symbol_ptr=>Lazy Symbol Pointers 懶加載符號表
_objc_classlist 方法名稱
... ...

5、dyld

dyld(the dynamic link editor)是蘋果的動態連接器,是蘋果操做系統的一個重要組成部分,在系統內容作好程序準備工做以後,交由dyld負責餘下的工做

系統庫的方法因爲是公用的,存放在共享緩存中,那麼咱們的MachO在調用系統方法時,dyld會將MachO裏調用存放在共享緩存中的方法進行符號綁定。這個符號在release環境 是會被自動去掉的,這也是咱們常用收集 bug 工具時須要恢復符號表的緣由

寫在後面

以上內容瞭解便可

相關文章
相關標籤/搜索