MachO文件
以一个简单的iOS项目,只有NSLog输出语句,然后编译(最好真机器),将编译后的MachO文件使用MachOView打开,分析其中内容:
编译后MachO--图1从图1可知MachO文件简单来区分可以分为4部分
1、Header 头部
用于快速确认CPU信息、文件类型等信息
2、Load Commands 加载命令
告诉loader如何设置并加载二进制数据
3、Segment段(分两部分)
3.1、Section Text 代码段(由代码编译成的指令集)
3.2、Section Data 数据段(含堆、栈、全局和静态变量)
存放:代码、字符常量、类、方法等
每个segment可以有0到多个section;每个段都有虚拟地址映射到进程的地址空间
4、Loader Info 链接信息
完整的MacO文件末端是一系列链接信息。其中包含了动态链接器用来链接可执行文件或者依赖所需的符号表、字符串表等
详细说明
一、Header
header截图从图中可知,通过Header可以获得CPU架构信息、文件类型等信息
Magic Number:魔数用来确定是32位还是64位 (MH_MAGIC_64,说明当前是64位)
CPU Type:CPU类型 (本例中是arm64)
CPU Subtype:CPU子类型()
File Type:用来确定文件类型(MH_EXECUTE, 可执行文件)
Number of Load Command:加载命令的数量,本例子中位23个加载命令(详解2中可对应下)
Size of Load Command:表示23个加载命令的总字节数为2888字节
Flags:表示二进制文件支持的功能,主要与系统的加载、链接有关
二、Load Commands 加载命令(本例子中共23条加载命令)
loader加载告诉loader如何设置并加载二进制数据
命令详解
1-5、LC_SEGMENT_64(xxx) 将该段映射到进程地址空间中
6、 LC_DYLD_INFO_ONLY 加载动态链接库
7、LC_SYMTAB 载入符号表地址
8、LC_DYSYMTAB 载入动态符号表地址
9、LC_LOAD_DYLINKER 加载动态加载库
10、LC_UUID 确定文件的唯一标识(crash文件中也会有,用来检查crash文件与dysm文件是否匹配)
11、
12、LC_SOURCE_VERSION 构建该二进制文件使用的源代码版本
13、LC_MAIN 设置程序主线程的入口地址和栈大小
14、LC_ENCRYPTION_INFO_64 获取加密信息
15-19、LC_LOAD_DYLIB(xxx) 加载额外的动态库
20、LC_RPATH Dyld维护一个称为运行路径列表的路径的当前堆栈。当遇到@rpath时,它会被替换为运行路径列表中的每个路径,直到找到可加载的dylib
21、LC_FUNCTION_STARTS 定义一个函数起始地址表,使调试器和其他程序易于看到一个地址是否在函数内
22、LC_DATA_IN_CODE 定义在代码段内的非指令的表
23、LC_CODE_SIGNATURE 获取应用签名信息
说明:一、二两部分让kernel知道如何读取MachO文件,并制定MachO文件的动态链接器用来完成后续的动态库加载,然后设置好程序的入口信息;后面的部分就相当于run起来之后,为每一个映射到虚拟内存中的指令操作提供真实的物理地址支持
三、Section Text代码段
text段从text段可以看到具体的类名、方法名等信息
data段图中红色部分,代表非懒加载符号表与懒加载符号表,这两个指针表,保存着与字符串标对应的函数指针
non lazy symbol pointer lazy symbol pointers四:Loader Info 链接信息
loaderinfo一共分四个区:
1、Rebase Info: pointer rebase的信息
2、Binding Info:non-lazy symbol pointer绑定需要的信息
3、Lazy Binding Info:lazy symbol pointer绑定需要的信息
4、Export Info:暴露给外部的符号的信息
该部分在hook代码中非常有用,根据mach-o的符号动态链接原理,让non-lazy/lazy symbol 指针重新指向对应的symbol stub代码位置,起到在runtime的hook