在windows上可执行文件的格式是exe,在Linux上ELF是可执行文件,而在苹果系统上,Mac OS X和ios系统上,可执行文件的格式是Mach-O格式。官方解释地址:https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/MachORuntime/index.html
1、Mach与Mach-O
这里先提醒大家一下,Mach不是Mac,Mac是苹果电脑Macintosh的简称,而Mach则是一种操作系统内核。Mach内核被NeXT公司的NeXTSTEP操作系统使用。在Mach上,一种可执行的文件格是就是Mach-O(Mach Object file format)。Mac OS X是Unix的“后代”,但所主要支持的可执行文件格式是Mach-O。
iOS是从OS X演变而来,所以同样是支持Mach-O格式的可执行文件。
2、ios可执行文件初探
作为ios开发者,我们比较熟悉ipa包,这种文件格式,然而,实际上这只是一个变相的zip的压缩包。我们将其解压之后发现
这其实是一个Payload的包 打开这个包 不能发现 这是一个test1.app的文件 也就是xcode生成的product文件
而这其实也就是一个文件夹,打开这个文件夹(显示包含内容)发现其中有一个同名的test1的可执行文件,这就是我们最终要寻找的在ios上的可执行文件
我们用file命令来查看这个文件的文件类型
这是一个64位的Mach-O 格式的可执行文件
3、Mach-O文件细究
根据苹果官方文档提供Mach-O文件的数据主体可分为三个部分
头部(Header)、加载命令(Load Commands)、数据(Data)
而数据部分则又被分割成了一段段的Segments。
下面我们使用otool工具来一探究竟
a) 先来查看下这个可执行文件的头部是怎样的
一堆看不明白的东西,分别予以解释
magic:0xfeedfacf 。这个东西是Mach-O的魔数。简单介绍下什么叫做魔数:很多类型的文件,其起始的几个字节的内容是固定的(或是有意填充,或是本就如此)。根据这几个字节的内容就可以确定文件类型,因此这几个字节的内容被称为魔数 (magic number)。
在OS X上 可执行文件的标识有这样几个魔数:cafebabe、feedface、feadfacf、还有就是以#!开头的。
cputype、cpusubtype:指的是CPU类型和CPU子类型
在/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/mach里找到machine.h的定义 如下图
这里有支持的cpu的详细编号命名 0代表ARM的格式都将支持
caps: 额 官网上都没介绍 这个待查
filetype 2:代表可执行文件
ncmds:指的是加载命令(load commands)的数量,例子中一共22个,编号0-21
sizeofcmds:表示要load的22个commands的总的大小
flags:可用来检验是否开启了PIE,如开启了则需要移除方能正常使用MachOView才能把文件结构检测出来
它有这么几种定义值:我们的文件无未定义引用 (MH_NOUNDEFS),是为动态链接器(MH_DYLDLINK),使用two-level名Cheng绑定(MH_TWOLEVEL)且应被加载到随机地址 (MH_PIE).
b)再来看加载命令(Load Commands) 截取其中一个Commands来分析
Load command 0 :command编号
cmdLC_SEGMENT_64:即是将文件中的段映射进内存中的地址空间
segname:16字节段名称
vmaddr:段虚拟内存的起始地址
vmsize:段虚拟内存的大小
fileoff:段在内存中的偏移量
filesize:段在文件中的大小
maxprot:段页面所需要的最高内存保护
initprot:段页面初始内存保护
nsects:段中包含section的数量
flags:其他杂项标志位
c)接下来看data,注意到command和data都是以segment为大单元字节,但是在data里还有section字节 所以重点介绍section的组织格式 截取一个section供分析
sectname:section的名字
segname:section归属为哪一个segment
addr:secction起始内存地址
size:section的大小
offset:该section的文件偏移量
align:字节大小对齐
reloff:重定位入口的文件偏移
nreloc:需要重定位的入口数量
flags:包含了section的类型和独自的属性
最后两项保留用
了解了这些 才能根据Mach-O的文件结构 去分析类的名称和类的方法 即是class-dump的实现原理,同时这也是MachOView等的分析原理
参考自:http://turingh.github.io/2016/03/07/mach-o%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E5%88%86%E6%9E%90/
附上otool命令大全
-f print the fat headers
-a print the archive header
-h print the mach header
-l print the load commands
-L print shared libraries used
-D print shared library id name
-t print the text section (disassemble with -v)
-p start dissassemble from routine name
-s print contents of section
-d print the data section
-o print the Objective-C segment
-r print the relocation entries
-S print the table of contents of a library
-T print the table of contents of a dynamic shared library
-M print the module table of a dynamic shared library
-R print the reference table of a dynamic shared library
-I print the indirect symbol table
-H print the two-level hints table
-G print the data in code table
-v print verbosely (symbolically) when possible
-V print disassembled operands symbolically
-c print argument strings of a core file
-X print no leading addresses or headers
-m don't use archive(member) syntax
-B force Thumb disassembly (ARM objects only)
-q use llvm's disassembler (the default)
-Q use otool(1)'s disassembler
-mcpu=arg use `arg' as the cpu for disassembly
-j print opcode bytes
-P print the info plist section as strings
-C print linker optimization hints
网友评论