歡迎閱讀iOS逆向系列(按序閱讀食用效果更加)緩存
以前在iOS逆向
系列中屢次提到MachO
,本文將帶着你們一探究竟bash
工具:MachOView 密碼:y2wr微信
MachO
實際上是Mach Object
文件格式的縮寫,是mac以及iOS上可執行文件的格式,相似於Windows上的PE格式(Portable Executable)、Linux上的elf格式(Executable and Linking Format)架構
它是一種用於可執行文件、目標代碼、動態庫的文件格式,做爲.out格式的替代,MachO提供了更強的擴展性app
$ file xxx.xx
函數
其實iPhone不一樣的型號對應的架構是不同的工具
架構 | 手機型號 |
---|---|
i386 | 32位模擬器 |
x86_64 | 64位模擬器 |
armv7 | iPhone四、iPhone4S |
armv7s | iPhone五、iPhone5C |
arm64 | iPhone5s——iPhoneX |
arm64e | iPhone XS、iPhone XS Max、iPhoneXR、iPhone11... |
新建一個工程,真機運行,查看可執行文件僅僅是一個arm64架構的 post
將項目最低適配系統調爲iOS9.0,真機運行Relese環境
爲何要改成iOS9.0呢?是由於iPhone5c等armv七、armv7s架構不支持iOS11.0性能
爲何要Relese環境運行呢?由於Xcode默認Debug只生成單一架構 ui
怎麼生成全部架構?Xcode10中只包含了v7和64,須要在Architectures
中添加
通用二進制文件(Universal binary)也被叫作胖二進制(Fat binary)
架構拆分
合併架構
通用二進制
大小爲342kb,四個架構大小爲80+80+80+81=321kb
What!爲何不是單純的1+1=2?
由於不一樣架構之間代碼部分是不共用的 (由於代碼的二進制文件不一樣的組合在不一樣的 cpu 上可能會是不一樣的意義),而公共資源文件是公用的
利用上述方法能夠給咱們的app瘦身
結論:
①胖二進制
拆分後再重組會獲得原始胖二進制
②通用二進制
的大小可能大於子架構大小之和,也可能小於,也可能等於,取決於公共資源文件
的多少
// 查看二進制文件
$ lipo -info xx
// 通用二進制文件
// 拆分二進制文件
lipo xxx -thin armv7 -output xxx
// 組合二進制文件
lipo -create x1 x2 x3 x4 -output xxx
複製代碼
用MachOView
打開會看到通用二進制文件
由Fat Header
和四個可執行文件
組成
可執行文件
是由
Header
、
Load commands
和
Data
組成
咱們能夠這麼理解,把
通用二進制文件
看做四本翻譯語言不一樣的書,每本書有
標題(header)
、
目錄(load commands)
、
內容(data)
另外咱們也能夠經過otool
命令行查看MachO文件結構
$ otool -f universe
複製代碼
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位)只多了一個保留字段
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 | 代碼簽名 |
data
是MachO文件中最大的部分,其中_TEXT段
、_DATA段
能給到不少信息
load commands
和data
之間還留有很多空間,給咱們留下了注入代碼的衝破口
名稱 | 做用 |
---|---|
_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 | 方法名稱 |
... | ... |
dyld(the dynamic link editor)是蘋果的動態連接器,是蘋果操做系統的一個重要組成部分,在系統內容作好程序準備工做以後,交由dyld負責餘下的工做
系統庫的方法因爲是公用的,存放在共享緩存中,那麼咱們的MachO在調用系統方法時,dyld會將MachO裏調用存放在共享緩存中的方法進行符號綁定。這個符號在release環境
是會被自動去掉的,這也是咱們常用收集 bug 工具時須要恢復符號表的緣由
以上內容瞭解便可