MachO文件
前言
Mach-O(Mach Object):Mach-O 文件是Mach object文件格式的缩写,它是可执行文件、目标代码、动态库的文件格式
主要包括:
- 目标文件.o
- 库文件
- .a
- .dylib
- Framework
- 可执行文件
- dyld
- .dsym
可以通过file命令查看文件类型
下面就来用file简单查看下这些文件
-
.o 文件
首先创建一个C文件通过Clang编译可以得到目标文件.o
1622547092622.png
通过 clang -c demo
.命令编译生成.o目标文件
通过file命令查看.o文件
1622547331572.png
说明.o文件是Mach-O文件类型的 64位(64-bit) object文件 x86_64架构
使用clang demo.o
生成a.out可执行文件
a.out 是一个可执行文件(executable)
- .a 文件 和 Framework
使用find ~/ -name "*.a"
命令可以找到家目录下的.a文件
找到之后查看一下.a
使用file命令查看.a文件
1622548473914.png
输出current ar archive random library这一坨不知道是什么鬼,有知道的大神可以帮忙解释一下
-
.dylib文件
使用file命令查看
1622548728531.png
4.dyld
1622549080217.png
dyld 是一个动态连接器(dynamic linker),包含多个架构的通用二进制文件(universal binary with 3 architectures)
通用二进制文件
通用二进制文件是苹果公司提出来的一种程序代码,能同时适用多种架构
实现同一个程序包为多种架构提供最理想的性能
因为存在针对多种架构的代码所以比单一架构的包体积大,又因为存在共同的非执行资源(代码以外的),所以比多个单一平台代码包的体积小
由于每种架构只运行对应架构的代码,所以运行起来时不会占用额外的内存
指令集
Armv6、armv7、armv7s、arm64都是arm处理器的指令集,所有指令集原则上都是向下兼容的,如iPhone4S的CPU默认指令集为armv7指令集,但它同时也兼容armv6指令集,只是使用armv6指令集时无法充分发挥其性能,即无法使用armv7指令集中的新特性,同理,iPhone5的处理器标配armv7s指令集,同时也支持armv7指令集,只是无法进行相关的性能优化,从而导致程序的执行效率没那么高。
需要注意的是iOS模拟器没有运行arm指令集,编译运行的是x86指令集,所以,只有在iOS设备上,才会执行设备对应的arm指令集。
移动设备默认指令集
- armv6 : iPhone, iPhone2, iPhone3G
- armv7(32bit):iPhone3GS, iPhone4, iPhone4S
- armv7S(32bit):iPhone4/iPhone4s (32位)
- arm64(64bit):iPhone5s(5s+)
- x86_64(64bit): 支持非M1Mac电脑的cpu架构(64位模拟器)
- i386:32位架构模拟器
iOS11(及以上)系统只支持64位的设备就是5s(及以上)的设备才能安装,Xcode所以选择iOS11及以上系统Archive时生成的包只包含arm64架构,选择iOS10及以下系统打出来的包才有可能包含多个架构
在Xcode -> build Settings->search "mach"可以选择编译生成的产物
1622552989804.png
Mach-O Type
- Executable:可执行文件
- Dynamic Library:动态库
- Static Library:静态库
- Bundle:Bundle
- Relocatable Object File:这个不知道是什么鬼
使用Xcode编译 选择最低支撑iOS11.0系统
1622553451512.png
查看编译生成包中的可执行文件
1622553521769.png
可以看到编译生成包中的可执行文件只支持arm64架构
再次选择最低支撑iOS10.0系统
1622553668749.png
可以看到编译生成包中的可执行文件变成了通用二进制文件支持arm64、和armv7两种架构
Xcode中编译架构设置 Build Settings -> Search "architectures" 下的Architecture
1622553897010.png
默认最多只支持arm64、armv7,可以修改这个配置支持更多架构
选择others加上armv7s然后再build
1622555144857.png
可以看到可执行文件多了armv7s架构
Lipo工具
-
使用lipo -info 可以查看MachO文件包含的架构
1622555459535.pnglipo -info MachO名称
-
使用lifo –thin 拆分某种架构
1622555576836.pnglipo MachO文件 –thin 架构 –output 输出文件路径
3.使用lipo -create 合并多种架构lipo -create MachO1 MachO2 -output 输出文件路径
MachO文件结构
1622631734095.png如图所示MachO文件包含三个部分:
1. Header
header 是MachO的头,其中包含了该MachO文件的一些信息
- 字节顺序、架构类型、加载指令数量等
- 通过Header快速确认一些信息,比如32位还是64位,处理器架构,文件类型等
2. Load commands
Load commands是一张包含一堆加载指令表
- 包含加载指令告诉dyld如何加载这个MachO
3. Data
Data是MachO中最大的部分
- 包含Segement的具体数据
首先用MachOView查看一下Header
1622636950762.png
在Xcode里command + shift + o 搜索Loader.h可以找到Header的定义
1622637106397.png
Header的具体内容及释义
1622632746599.png
使用MachOView
查看MachO文件
其中Load commands各条加载指令的含义如下:
- LC_SEGMENT_64:将文件中(32位或者64位)的段映射到进程地址空间中
- LC_DYLD_INFO_ONLY:动态连接相关信息
- LC_SYMTAB:符号地址
- LC_DYSYMTAB:动态符号表地址
- LC_LOAD_DYLINKER:使用什么加载,iOS的App使用dyld加载
- LC_UUID:文件的UUID
- LC_VERSION_MIN_IPHONEOS:最低支持的操作系统版本
- LC_SOURCE_VERSION:源代码版本
- LC_MAIN:程序主线程的入口地址和栈大小
- LC_ENCRYPTION_INFO_64 加密信息
- LC_LOAD_DYLIB:依赖库的路径,包含三方库
- LC_RPATH:dyld维护一个称为运行路径列表的路径的当前堆栈。当遇到@rpath时,它会被替换为运行路径列表中的每个路径,直到找到可加载的dylib(此项释义是网上摘录的还没弄懂啥意思)
- LC_FUNCTION_STARTS:函数起始地址表
- LC_DATA_IN_CODE:定义在代码段内的非指令的表
- LC_CODE_SIGNATURE:代码签名
接下来详细看下各个command的内容:
LC_SEGMENT_64
- VM Address:运行时加载到内存(虚拟内存)的起始地址(要加上ALSR才是真正的内存地址)
- VM Size:内存中占用大小
- File Offset:在文件中的偏移地址
- File Size:在文件中占用大小
PS:可以看到_TEXT的File Offset是0,所以MachO文件是以代码段起始的
LC_DYLD_INFO_ONLY
- Rebase Info Offset:重定向开始位置的偏移地址
- Rebase Info Size:需要重定向的内容的大小
- Binding Info Offset:绑定数据的偏移地址
- Binding Info Size:绑定数据的大小
- Weak Binding Info Offset:弱绑定
- Weak Binding Info Size:
- Lazy Binding Info Offset:懒绑定(用到的时候再绑定)
- Lazy Binding Info Size:
- Export Info Offset:对外开放的函数
- Export Info Size:
LC_SYMTAB符号相关(函数名称,函数地址)
LC_MAIN 逆向找不到切入点的时候经常用到这个,当别人做了防护App启动就闪退时可以断住这个函数再做分析
使用 otool
工具可以查看MachO的信息
Load commands的下面就是Data
Data分为_TEXT段(代码段)和_DATA段(数据段)
1622639877442.png
其中Section64(__TEXT,__text)
是主程序代码
Section64(__TEXT,__stubs)
和Section64(__TEXT,__stub_helper)
是做符号绑定的
Section64(__TEXT,__objc_methname)
是方法名称
Section64(__TEXT,__objc_classname)
是类名称
Section64(__TEXT,__objc_methtype)
是方法类型
其他内容后面在用到的时候再补充
网友评论