从macho中解析类名

1什么是macho

2 macho总体描述

3以查询一个类名为例,说明查找过程

1什么是macho

macho是mac os, ios可执行文件格式,类似windows上的pe和linux上的elf。macho是源码通过编译连接产生。

2 macho总体描述

先用文本打开,来个感官认识下,如下图:


macho也是文件,只不过组织结构文本查看器不能解析。

下面整体看下macho的结构。

文件的开始32个Byte是头部,头部包含的信息中包含要加载的指令条数。

接下来是要加载的指令。

这些指令以段(Segment)分为多个。

有的段又分为多个区(Section)。

上面的Section只是索引,包含该section在整个文件中的位置和大小,如果要查看section具体的数据,就要通过偏移位置和大小去查找。

下面是基本结构图:


接下来具体讲解下每部分的含义。

要参考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可以转换为一个结构体表示。结构体的定义如下。

/*

* 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魔数标识macho文件是多少位的,是不是fat格式(多个架构合并),是不是小端序

前4byte为魔数,根据魔数可以判断macho是32位还是64位,还记录着是大端序或小端序

#defineMH_MAGIC0xfeedface/* the mach magic number */32

#defineMH_CIGAM0xcefaedfe/* NXSwapInt(MH_MAGIC) */32,解析需要转换成小端序

#defineMH_MAGIC_640xfeedfacf/* the 64-bit mach magic number */64

#defineMH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */64位解析需要转换成小端序

其中0xCAFEBABE为多个架构的mach-o

2.1.2 cpu类型,标识该macho需要在哪些类型的cpu上运行

cputype如下,


cputype和cpusubtype具体含义查看头文件machine.h

2.1.3文件类型filetype标识文件的类型,是可执行文件还是其他类型的文件

部分类型说明如下:详细的说明参考文件loader.h


2.1.4 flags标识macho的一些特性,比如是否包含未定义的引用,如果是镜像是否有二级命名空间绑定。

部分定义见下面,详细的定义参考loader.h


2.1.5加载命令的信息ncmdssizeofcmds,依据这些信息来解析加载命令

ncmds是加载命令的个数。sizeofcmds是加载命令索引的大小。

2.2解析加载命令

2.2.1每一个加载命令至少还有两个元素,第一个是类型,第二个是大小

具体下面结构体

struct load_command {

uint32_t cmd;/* type of load command */

uint32_t cmdsize;/* total size of command in bytes */

};

cmd,加载命令的类型定义如下(其中动态库的定义看文件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包含改命令中的所有内容的大小,比如segment中的section。

其中常见的加载命令解释看下图:



2.2.2

解析一个

segment

Segment的定义看下面的结构体

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:该段所在内存的开始虚拟地址。64位虚拟地址的起始值是0x100000000,32位0x4000

fileoff:该段从macho文件开始位置的偏移值,从0开始计算

vmsize:该段占用虚拟内存的大小

filesize:该段占用文件中的大小,和vmsize相等。

nsects:该段中包含的区的个数。

2.2.3解析一个区

其中一个区的定义如下:

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标识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

常见的区的解释见下图



3

解析类名

需要用的工具有MachoViewer和Hopper

用machoViewer打开macho文件。

如下图:


找到Data Segment中的_objc_classlist对应的section


记录下对应的Address


用Hopper打开macho文件

键盘输入大写字母G(跳到指定地址),或者选择Navigate-> Go To Address or Symbol进入挑战页面。

输入_objc_classlist的地址。

如下图


点击Go按钮跳到_objc_classlist的地址


上图显示有三个类,AppDelegate, MasterViewController, DetailViewController

但是从macho文件来解析,这是三个地址,这三个类名是Hopper解析号之后加到显示的注释上了。

选择查看原件,红框里面就是MasterViewController对应的地址


双击_OBJC_CLASS_$_MasterViewController,可以跳转到MasterViewController的引用处。

如下图:



双击MasterViewController_data可以跳转的MasterViewController的详细信息处。(同样这里MasterViewController_data也只是地址)

跳转之后如下图:



其中有一相是类名,这里是地址,双击可以到具体类名的地方。

跳转之后如下图:


到此查找类名结束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容