最近用純Swift參照很是知名的Aspects寫了個Aspect,是基於Runtime進行方法交換,正好以前據說過能夠經過fishhook動態修改 C 語言函數,全部就研究了一下,可是要想看懂fishhook,須要先了解Mach-O,這一塊一直是個人知識盲點,這一次索性花些時間一併消化一下。蘋果源碼查看這裏。html
Mach-O,是Mach object文件格式的縮寫,是一種可執行文件、目標代碼、共享程序庫、動態加載代碼和核心dump。是a.out格式的一種替代。Mach-O提供了更強的擴展性,並提高了符號表中信息的訪問速度。ios
*
* Constants for the filetype field of the mach_header
*/
#define MH_OBJECT 0x1 /* relocatable object file */
#define MH_EXECUTE 0x2 /* demand paged executable file */
#define MH_FVMLIB 0x3 /* fixed VM shared library file */
#define MH_CORE 0x4 /* core file */
#define MH_PRELOAD 0x5 /* preloaded executable file */
#define MH_DYLIB 0x6 /* dynamically bound shared library */
#define MH_DYLINKER 0x7 /* dynamic link editor */
#define MH_BUNDLE 0x8 /* dynamically bound bundle file */
#define MH_DYLIB_STUB 0x9 /* shared library stub for static */
/* linking only, no section contents */
#define MH_DSYM 0xa /* companion file with only debug */
/* sections */
#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */
複製代碼
咱們看到Mach-O有多種文件類型,常見的格式:git
可執行文件github
objcetbash
DYLIB: 動態庫文件架構
動態鏈接器,dynamic linkerapp
DSYM:分析APP崩潰信息ide
很是推薦 Mach-O 文件一 ,這個也是從這篇文章拿來的。函數
test.c 的 C 文件post
int main(){
return 0;
}
複製代碼
編譯一下 clang -c test.c
,生成 test.o 文件
經過 file 命令查看一下 file test.o
,能夠看到,test.o 爲 Mach-O 文件,object 文件 test.o: Mach-O 64-bit object x86_64
經過 clang 連接一下目標文件test.o clang test.o
,text.c 就轉變成一個 a.out 的可執行文件
執行./a.out
,轉換執行過程
執行clang -o test1 test.o
,連接 test.0 目標文件,生成 test1 的可執行文件
執行clang -o test2 test.c
,直接一次性將源文件生成 test2 的可執行文件
經過上圖,能夠看出Mach-O主要由如下三部分組成:
** 來用MachOView驗證一下該示例的MachO文件結構:**
簡單瀏覽mach-o可執行文件,具體能夠分爲幾個部分:
/*
* The 64-bit mach header appears at the very beginning of object files for
* 64-bit architectures.
*/
struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
複製代碼
Load commands跟在mach_header以後。全部命令的總大小由mach_header中的sizeofcmds字段給出。oad commands必須有前兩個字段cmd和cmdsize。cmd字段以該命令類型的常量填充。每一個命令類型都有專門針對它的結構。cmdsize字段是特定加載命令結構的字節大小加上跟隨它的任何一部分,這是加載命令(即節結構、字符串等)的一部分。爲了前進到下一個加載命令,cmdsize能夠被添加到當前加載命令的偏移量或指針中。32位架構的cmdsize必須是4字節的倍數,對於64位架構必須是8字節的倍數(這些永遠是任何加載命令的最大對齊)。填充的字節必須爲零。目標文件中的全部表也必須遵循這些規則,以便文件能夠進行內存映射。不然,這些表的指針在某些機器上沒法正常工做或根本沒法正常工做。全部padding歸零像對象將比較逐字節。
/*
* The segment load command indicates that a part of this file is to be
* mapped into the task's address space. The size of this segment in memory, * vmsize, maybe equal to or larger than the amount to map from this file, * filesize. The file is mapped starting at fileoff to the beginning of * the segment in memory, vmaddr. The rest of the memory of the segment, * if any, is allocated zero fill on demand. The segment's maximum virtual
* memory protection and initial virtual memory protection are specified
* by the maxprot and initprot fields. If the segment has sections then the
* section structures directly follow the segment command and their size is
* reflected in cmdsize.
*/
struct segment_command { /* for 32-bit architectures */
uint32_t cmd; /* LC_SEGMENT */
uint32_t cmdsize; /* includes sizeof section structs */
char segname[16]; /* segment name */
uint32_t vmaddr; /* memory address of this segment */
uint32_t vmsize; /* memory size of this segment */
uint32_t fileoff; /* file offset of this segment */
uint32_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
};
複製代碼
部分的 Segment (主要指的 __TEXT 和 __DATA)能夠進一步分解爲 Section。之因此按照 Segment -> Section 的結構組織方式,是由於在同一個 Segment 下的 Section,能夠控制相同的權限,也能夠不徹底按照 Page 的大小進行內存對其,節省內存的空間。而 Segment 對外總體暴露,在程序載入階段映射成一個完整的虛擬內存,更好的作到內存對齊。
struct section_64 { /* for 64-bit architectures */
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint64_t addr; /* memory address of this section */
uint64_t size; /* size in bytes of this section */
uint32_t offset; /* file offset of this section */
uint32_t align; /* section alignment (power of 2) */
uint32_t reloff; /* file offset of relocation entries */
uint32_t nreloc; /* number of relocation entries */
uint32_t flags; /* flags (section type and attributes)*/
uint32_t reserved1; /* reserved (for offset or index) */
uint32_t reserved2; /* reserved (for count or sizeof) */
uint32_t reserved3; /* reserved */
};
複製代碼
段的命名規則是兩個下劃線緊跟着大寫字母(如__TEXT),而section的命名則是兩個下劃線緊跟着小寫字母(__text)。
下面列出段中可能包含的section:
- __TEXT段:
__text, __cstring, __picsymbol_stub, __symbol_stub, __const, __litera14, __litera18;
- __DATA段
__data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __const, __mod_init_func, __mod_term_func, __bss, __commom;
- __IMPORT段
__jump_table, __pointers;
其中__TEXT段中的__text是實際上的代碼部分;__DATA段的__data是實際的初始數據。
關於Mach-o文件格式就講完了,若是對程序從加載到執行過程感興趣能夠看Mach-O文件格式和程序從加載到執行過程 和 趣探 Mach-O:加載過程,講的很詳細。
MachO 文件結構詳解
Mach-O 文件一
Mach-O文件格式和程序從加載到執行過程
iOS逆向基礎Mach-O文件(1)
Mach-O 文件格式探索