1什么是macho
2 macho總體描述
3以查詢一個類名為例,說明查找過程
1什么是macho
macho是mac os, ios可執(zhí)行文件格式,類似windows上的pe和linux上的elf滤祖。macho是源碼通過編譯連接產(chǎn)生。
2 macho總體描述
先用文本打開慧邮,來個感官認(rèn)識下,如下圖:
macho也是文件,只不過組織結(jié)構(gòu)文本查看器不能解析鳍鸵。
下面整體看下macho的結(jié)構(gòu)。
文件的開始32個Byte是頭部,頭部包含的信息中包含要加載的指令條數(shù)草讶。
接下來是要加載的指令祭椰。
這些指令以段(Segment)分為多個泥张。
有的段又分為多個區(qū)(Section)莹痢。
上面的Section只是索引种蘸,包含該section在整個文件中的位置和大小,如果要查看section具體的數(shù)據(jù)竞膳,就要通過偏移位置和大小去查找航瞭。
下面是基本結(jié)構(gòu)圖:
接下來具體講解下每部分的含義。
要參考loader.h(/usr/include/mach-o/loader.h或者https://opensource.apple.com/source/xnu/xnu-1456.1.26/EXTERNAL_HEADERS/mach-o/loader.h)
前32Byte可以轉(zhuǎn)換為一個結(jié)構(gòu)體表示坦辟。結(jié)構(gòu)體的定義如下刊侯。
/*
* The 32-bit mach header appears at the very beginning of the object file for
* 32-bit architectures.
*/
struct mach_header {
uint32_tmagic;/* mach magic number identifier */
cpu_type_tcputype;/* cpu specifier */
cpu_subtype_tcpusubtype;/* machine specifier */
uint32_tfiletype;/* type of file */
uint32_tncmds;/* number of load commands */
uint32_tsizeofcmds;/* the size of all the load commands */
uint32_tflags;/* flags */
};
/*
* The 64-bit mach header appears at the very beginning of object files for
* 64-bit architectures.
*/
struct mach_header_64 {
uint32_tmagic;/* mach magic number identifier */
cpu_type_tcputype;/* cpu specifier */
cpu_subtype_tcpusubtype;/* machine specifier */
uint32_tfiletype;/* type of file */
uint32_tncmds;/* number of load commands */
uint32_tsizeofcmds;/* the size of all the load commands */
uint32_tflags;/* flags */
uint32_treserved;/* reserved */
};
2.1.1魔數(shù)標(biāo)識macho文件是多少位的,是不是fat格式(多個架構(gòu)合并),是不是小端序
前4byte為魔數(shù)锉走,根據(jù)魔數(shù)可以判斷macho是32位還是64位,還記錄著是大端序或小端序
#defineMH_MAGIC0xfeedface/* the mach magic number */是32位
#defineMH_CIGAM0xcefaedfe/* NXSwapInt(MH_MAGIC) */是32位,解析需要轉(zhuǎn)換成小端序
#defineMH_MAGIC_640xfeedfacf/* the 64-bit mach magic number */是64位
#defineMH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */是64位解析需要轉(zhuǎn)換成小端序
其中0xCAFEBABE為多個架構(gòu)的mach-o
2.1.2 cpu類型滨彻,標(biāo)識該macho需要在哪些類型的cpu上運行
cputype如下,
cputype和cpusubtype具體含義查看頭文件machine.h
2.1.3文件類型filetype標(biāo)識文件的類型挪蹭,是可執(zhí)行文件還是其他類型的文件
部分類型說明如下:詳細的說明參考文件loader.h
2.1.4 flags標(biāo)識macho的一些特性亭饵,比如是否包含未定義的引用,如果是鏡像是否有二級命名空間綁定。
部分定義見下面嚣潜,詳細的定義參考loader.h
2.1.5加載命令的信息ncmds和sizeofcmds,依據(jù)這些信息來解析加載命令
ncmds是加載命令的個數(shù)冬骚。sizeofcmds是加載命令索引的大小椅贱。
2.2解析加載命令
2.2.1每一個加載命令至少還有兩個元素,第一個是類型,第二個是大小
具體下面結(jié)構(gòu)體
struct load_command {
uint32_t cmd;/* type of load command */
uint32_t cmdsize;/* total size of command in bytes */
};
cmd懂算,加載命令的類型定義如下(其中動態(tài)庫的定義看文件loader.h)
/* Constants for the cmd field of all load commands, the type */
#defineLC_SEGMENT0x1/* segment of this file to be mapped */
#defineLC_SYMTAB0x2/* link-edit stab symbol table info */
#defineLC_SYMSEG0x3/* link-edit gdb symbol table info (obsolete) */
#defineLC_THREAD0x4/* thread */
#defineLC_UNIXTHREAD0x5/* unix thread (includes a stack) */
#defineLC_LOADFVMLIB0x6/* load a specified fixed VM shared library */
#defineLC_IDFVMLIB0x7/* fixed VM shared library identification */
#defineLC_IDENT0x8/* object identification info (obsolete) */
#define LC_FVMFILE0x9/* fixed VM file inclusion (internal use) */
#define LC_PREPAGE0xa/* prepage command (internal use) */
#defineLC_DYSYMTAB0xb/* dynamic link-edit symbol table info */
#defineLC_LOAD_DYLIB0xc/* load a dynamically linked shared library */
#defineLC_ID_DYLIB0xd/* dynamically linked shared lib ident */
#define LC_LOAD_DYLINKER 0xe/* load a dynamic linker */
#define LC_ID_DYLINKER0xf/* dynamic linker identification */
#defineLC_PREBOUND_DYLIB 0x10/* modules prebound for a dynamically */
/*linked shared library */
#defineLC_ROUTINES0x11/* image routines */
#defineLC_SUB_FRAMEWORK 0x12/* sub framework */
#defineLC_SUB_UMBRELLA 0x13/* sub umbrella */
#defineLC_SUB_CLIENT0x14/* sub client */
#defineLC_SUB_LIBRARY0x15/* sub library */
#defineLC_TWOLEVEL_HINTS 0x16/* two-level namespace lookup hints */
#defineLC_PREBIND_CKSUM0x17/* prebind checksum */
cmdsize包含改命令中的所有內(nèi)容的大小,比如segment中的section。
其中常見的加載命令解釋看下圖:
2.2.2
解析一個
segment
Segment的定義看下面的結(jié)構(gòu)體
struct segment_command { /* for 32-bit architectures */
uint32_tcmd;/* LC_SEGMENT */
uint32_tcmdsize;/* includes sizeof section structs */
charsegname[16];/* segment name */
uint32_tvmaddr;/* memory address of this segment */
uint32_tvmsize;/* memory size of this segment */
uint32_tfileoff;/* file offset of this segment */
uint32_tfilesize;/* amount to map from the file */
vm_prot_tmaxprot;/* maximum VM protection */
vm_prot_tinitprot;/* initial VM protection */
uint32_tnsects;/* number of sections in segment */
uint32_tflags;/* flags */
};
/*
* The 64-bit segment load command indicates that a part of this file is to be
* mapped into a 64-bit task's address space.If the 64-bit segment has
* sections then section_64 structures directly follow the 64-bit segment
* command and their size is reflected in cmdsize.
*/
struct segment_command_64 { /* for 64-bit architectures */
uint32_tcmd;/* LC_SEGMENT_64 */
uint32_tcmdsize;/* includes sizeof section_64 structs */
charsegname[16];/* segment name */
uint64_tvmaddr;/* memory address of this segment */
uint64_tvmsize;/* memory size of this segment */
uint64_tfileoff;/* file offset of this segment */
uint64_tfilesize;/* amount to map from the file */
vm_prot_tmaxprot;/* maximum VM protection */
vm_prot_tinitprot;/* initial VM protection */
uint32_tnsects;/* number of sections in segment */
uint32_tflags;/* flags */
};
segname:是該段的名字,占用16個byte庇麦。
vmaddr:該段所在內(nèi)存的開始虛擬地址。64位虛擬地址的起始值是0x100000000,32位0x4000
fileoff:該段從macho文件開始位置的偏移值,從0開始計算
vmsize:該段占用虛擬內(nèi)存的大小
filesize:該段占用文件中的大小,和vmsize相等。
nsects:該段中包含的區(qū)的個數(shù)欧引。
2.2.3解析一個區(qū)
其中一個區(qū)的定義如下:
struct section { /* for 32-bit architectures */
charsectname[16];/* name of this section */
charsegname[16];/* segment this section goes in */
uint32_taddr;/* memory address of this section */
uint32_tsize;/* size in bytes of this section */
uint32_toffset;/* file offset of this section */
uint32_talign;/* section alignment (power of 2) */
uint32_treloff;/* file offset of relocation entries */
uint32_tnreloc;/* number of relocation entries */
uint32_tflags;/* flags (section type and attributes)*/
uint32_treserved1;/* reserved (for offset or index) */
uint32_treserved2;/* reserved (for count or sizeof) */
};
struct section_64 { /* for 64-bit architectures */
charsectname[16];/* name of this section */
charsegname[16];/* segment this section goes in */
uint64_taddr;/* memory address of this section */
uint64_tsize;/* size in bytes of this section */
uint32_toffset;/* file offset of this section */
uint32_talign;/* section alignment (power of 2) */
uint32_treloff;/* file offset of relocation entries */
uint32_tnreloc;/* number of relocation entries */
uint32_tflags;/* flags (section type and attributes)*/
uint32_treserved1;/* reserved (for offset or index) */
uint32_treserved2;/* reserved (for count or sizeof) */
uint32_treserved3;/* reserved */
};
flag標(biāo)識section的一些特性听系,部分定義看下面
#define S_NON_LAZY_SYMBOL_POINTERS 0x6/* section with only non-lazy symbol pointers */
#define S_LAZY_SYMBOL_POINTERS 0x7/* section with only lazy symbolpointers */
#define S_SYMBOL_STUBS0x8/* section with only symbol stubs, byte size of stub in
the reserved2 field */
#define S_MOD_INIT_FUNC_POINTERS 0x9 /* section with only function pointers for
initialization*/
#define S_MOD_TERM_FUNC_POINTERS0xa/* section with only function pointers for termination*/
#define S_COALESCED0xb/* section contains symbols that are to be coalesced */
#define S_GB_ZEROFILL0xc/* zero fill on demand section
常見的區(qū)的解釋見下圖
3
解析類名
需要用的工具有MachoViewer和Hopper
用machoViewer打開macho文件。
如下圖:
找到Data Segment中的_objc_classlist對應(yīng)的section
記錄下對應(yīng)的Address
用Hopper打開macho文件
鍵盤輸入大寫字母G(跳到指定地址),或者選擇Navigate-> Go To Address or Symbol進入挑戰(zhàn)頁面睡雇。
輸入_objc_classlist的地址萌衬。
如下圖
點擊Go按鈕跳到_objc_classlist的地址
上圖顯示有三個類,AppDelegate, MasterViewController, DetailViewController
但是從macho文件來解析,這是三個地址,這三個類名是Hopper解析號之后加到顯示的注釋上了它抱。
選擇查看原件秕豫,紅框里面就是MasterViewController對應(yīng)的地址
雙擊_OBJC_CLASS_$_MasterViewController,可以跳轉(zhuǎn)到MasterViewController的引用處。
如下圖:
雙擊MasterViewController_data可以跳轉(zhuǎn)的MasterViewController的詳細信息處观蓄。(同樣這里MasterViewController_data也只是地址)
跳轉(zhuǎn)之后如下圖:
其中有一相是類名混移,這里是地址,雙擊可以到具體類名的地方侮穿。
跳轉(zhuǎn)之后如下圖:
到此查找類名結(jié)束歌径。