本文主要介紹Mach-O文件的內(nèi)部結(jié)構(gòu)的演示

Mach-O內(nèi)部結(jié)構(gòu)
因為MachO文件本身是一種文件格式,所以我們一定需要了解其文件內(nèi)部結(jié)構(gòu)。
Mach-O 的組成結(jié)構(gòu)主要分為三部分
-
Header包含該二進制文件的一般信息- 字節(jié)順序、架構(gòu)類型、加載指令的數(shù)量等。
- 使得可以快速確認一些信息,比如當(dāng)前文件用于32位還是64位,對應(yīng)的處理器是什么、文件類型是什么
-
Load commands(加載命令) 一張包含很多內(nèi)容的表- 內(nèi)容包括
區(qū)域的位置、符號表、動態(tài)符號表等。
- 內(nèi)容包括
-
Data(數(shù)據(jù)) 通常是對象文件中最大的部分- 包含
Segement的具體數(shù)據(jù),首先是分段,然后段中`分節(jié)
- 包含
終端命令:otool
在終端中,我們通過otool 查看Mach-O的一些指令
- 查看Mach-O的Header信息:
otool -f 12-macho
MachOView軟件
- 通過
MachOView查看Mach-O文件
- 驗證ARM_V7與ARM_V7s之間是否是分頁?
* ARM_V7與ARM_V7s的差值:`16384+79376 - 98304 = -2544`
* `ARM_V7`的大?。篳-2544 - 79376 = - 81920`,查看這個值是否是 pageSize(4096)的倍數(shù)
* 是否是PAGESIZE的倍數(shù):`81920 / 4096 = 20`(MacOS中),但是由于是iOS,所以 `20 / 4 = 5`頁,說明是分頁了,即按頁對齊
兩者對比
- otool與MachOView查看的Mach-O進行對比
MachOView演示
通過MachOView查看Mach-O結(jié)構(gòu),分為三部分:Header、Load Commands、Data
- 1、查看
arm64下Mach-O的Header
- 2、查看
Load Commands
* `VM Addr` : 虛擬內(nèi)存地址
-`VM Size`: 虛擬內(nèi)存大小,在運行時刻,在內(nèi)存中的大小,4g
- 64位地址:0x12345678a2345678
- 32位地址:0x12345678
* `File offset`: 數(shù)據(jù)在文件中偏移量
* `File size`: 數(shù)據(jù)在文件中的大小
- 3、 Section中分為兩大類:
__TEXT(代碼)、__DATA(數(shù)據(jù))
1、Header的數(shù)據(jù)結(jié)構(gòu)
- 在
CMD+shift+O搜索loader.h,找到Mach_Header_64(arm64架構(gòu))的數(shù)據(jù)結(jié)構(gòu)如下所示,與mach_header相比,只是多了一個reverse
<!--1、mach_header-->
struct mach_header {
uint32_t magic; /* 魔數(shù),快速定位屬于64還是32位 */
cpu_type_t cputype; /* CPU類型 */
cpu_subtype_t cpusubtype; /* CPU的具體類型 */
uint32_t filetype; /* 文件類型,比如可執(zhí)行文件 */
uint32_t ncmds; /* Load Commands的條數(shù) */
uint32_t sizeofcmds; /* Load Commands的大小 */
uint32_t flags; /* 標(biāo)志位標(biāo)識二進制文件支持的功能,主要是和系統(tǒng)加載、鏈接有關(guān) */
};
<!--2、mach_header_64-->
struct mach_header_64 {
uint32_t magic; /* 魔數(shù),快速定位屬于64還是32位 */
cpu_type_t cputype; /* CPU類型 */
cpu_subtype_t cpusubtype; /* CPU的具體類型 */
uint32_t filetype; /* 文件類型,比如可執(zhí)行文件 */
uint32_t ncmds; /* Load Commands的條數(shù) */
uint32_t sizeofcmds; /* Load Commands的大小 */
uint32_t flags; /* 標(biāo)志位標(biāo)識二進制文件支持的功能,主要是和系統(tǒng)加載、鏈接有關(guān) */
uint32_t reserved; /* reserved */
};
- 2、查看filetype種類
OC文件:
#define MH_OBJECT 0x1可執(zhí)行文件:
#define MH_EXECUTE 0x2...
2、Load Commands
Load Commands中的相關(guān)字段含義如下所示
| LoadCommands | 說明 |
|---|---|
| LC_SEGMENT_64 | 將文件中(32位或64位)的段映射到進程地址空間中,主要分為__TEXT、__DATA、LINKEDIT幾大塊 |
| LC_DYLD_INFO_ONLY | 動態(tài)鏈接相關(guān)信息 |
| LC_SYMTAB | 符號地址 |
| DYSYMTAB | 動態(tài)符號表地址 |
| LC_LOAD_DYLINKER | 使用誰加載,我們使用dyld |
| LC_UUID | Mach-O文件的唯一識別標(biāo)識 UUID |
| LC_VERSION_MIN_MACOSX | 支持最低的操作系統(tǒng)版本 |
| LC_SOURCE_VERSION | 源代碼版本 |
| LC_MAIN | 設(shè)置程序主線程的入口地址和棧大小 |
| LC_ENCRYPTION_INFO_64 | 加密信息 |
| LC_LOAD_DYLIB | 依賴庫的路徑,包含三方庫 |
| LC_FUNCTION_STARTS | 函數(shù)起始地址表 |
| LC_CODE_SIGNATURE | 代碼簽名 |
演示
- 1、
LC_SEGMENT_64中__TEXT、__DATA、LINKEDIT的對應(yīng)關(guān)系如下圖所示
- 2、查看
LC_DYLD_INFO_ONLY動態(tài)鏈接信息
其中Rebase是重定向,重定向過程簡述如下:
* 1)`代碼段`放入Mach-O文件,在編譯時期,會生成一個偏移地址
* 2)在運行時期,`mach-o文件放入虛擬內(nèi)存`,其內(nèi)存也是隨機變化的(由系統(tǒng)分配 - ASLR)
* 3)所以之前的代碼段在mach-O中偏移值就不性能使用了,需要通過`ASLR + Rebase Info Offset重定向`,主要改變的是匯編代碼
- 3、查看
LC_SYMTAB符號地址
- 4、查看
LC_LOAD_DYLINKER,使用誰鏈接,這里使用的是dyld
- 6、查看
LC_UUID,mach-o文件識別的唯一標(biāo)識
- 7、查看
LC_VERSION_MIN_MACOSX,支持的最低版本信息
- 8、查看
LC_SOURCE_VERSION,代碼版本
- 9、查看
LC_MAIN,入口函數(shù)
* **作用**:用于逆向時找不到切入點時(例如:做了防護,運行就閃退),可以從這里找到
- 10、查看
LC_ENCRYPTION_INFO_64,此時Crypt ID為0,表示還沒有加密
3、Data
- 1、如果我們想快速定位代碼段,需要通過
LC_SEGMENT_64(__TEXT)中的VM Adress
- 2、查看
代碼段的起始位置
也可以通過`objdump`命令來查看:`objdump --macho -d 12-macho`
從這里看出,正好與Mach-O文件中的對應(yīng)
- 3、查看stub、stub_helper:主要是用于符號綁定,這里的
0x1000065d4全是指向的000325D4偏移,且前面6句匯編都是在做符號綁定
- 4、查看外部符號表(即 調(diào)用外部函數(shù),只有在運行時才綁定),有兩個:懶加載、非懶加載
這里是先`綁定`專門`用來綁定外部的函數(shù)`,在用這個函數(shù)去綁定其他函數(shù)
總結(jié)
作為一個開發(fā)者,有一個學(xué)習(xí)的氛圍跟一個交流圈子特別重要,這是一個我的iOS開發(fā)交流群:130 595 548,不管你是小白還是大牛都歡迎入駐 ,讓我們一起進步,共同發(fā)展?。ㄈ簝?nèi)會免費提供一些群主收藏的免費學(xué)習(xí)書籍資料以及整理好的幾百道面試題和答案文檔?。?/p>
-
Mach-O內(nèi)部結(jié)構(gòu)
Header:用于快速確定該文件的CPU類型、文件類型Load Commands:指示加載器如何設(shè)置并加載二進制數(shù)據(jù)-
Data:存放數(shù)據(jù),例如代碼、數(shù)據(jù)、字符串常量、類、方法等,-
Section中分為兩大類:__TEXT(代碼)、__DATA(數(shù)據(jù))
-
可以通過
otool命令查看Mach-O信息,例如查看Header信息:otool -f 12-macho可以通過
objdump命令來查看代碼段:objdump --macho -d 12-macho