欢迎阅读iOS逆向系列(按序阅读食用效果更加)缓存
以前在iOS逆向
系列中屡次提到MachO
,本文将带着你们一探究竟bash
工具:MachOView 密码:y2wr微信
MachO
实际上是Mach Object
文件格式的缩写,是mac以及iOS上可执行文件的格式,相似于Windows上的PE格式(Portable Executable)、Linux上的elf格式(Executable and Linking Format)架构
它是一种用于可执行文件、目标代码、动态库的文件格式,做为.out格式的替代,MachO提供了更强的扩展性app
$ file xxx.xx
函数
其实iPhone不一样的型号对应的架构是不同的工具
架构 | 手机型号 |
---|---|
i386 | 32位模拟器 |
x86_64 | 64位模拟器 |
armv7 | iPhone四、iPhone4S |
armv7s | iPhone五、iPhone5C |
arm64 | iPhone5s——iPhoneX |
arm64e | iPhone XS、iPhone XS Max、iPhoneXR、iPhone11... |
新建一个工程,真机运行,查看可执行文件仅仅是一个arm64架构的 post
Relese环境
为何要改成iOS9.0呢?是由于iPhone5c等armv七、armv7s架构不支持iOS11.0性能
为何要Relese环境运行呢?由于Xcode默认Debug只生成单一架构 ui
怎么生成全部架构?Xcode10中只包含了v7和64,须要在Architectures
中添加
通用二进制文件(Universal binary)也被叫作胖二进制(Fat binary)
架构拆分
合并架构
通用二进制
大小为342kb,四个架构大小为80+80+80+81=321kb
What!为何不是单纯的1+1=2?
由于不一样架构之间代码部分是不共用的 (由于代码的二进制文件不一样的组合在不一样的 cpu 上可能会是不一样的意义),而公共资源文件是公用的
利用上述方法能够给咱们的app瘦身
结论:
①胖二进制
拆分后再重组会获得原始胖二进制
②通用二进制
的大小可能大于子架构大小之和,也可能小于,也可能等于,取决于公共资源文件
的多少
// 查看二进制文件
$ lipo -info xx
// 通用二进制文件
// 拆分二进制文件
lipo xxx -thin armv7 -output xxx
// 组合二进制文件
lipo -create x1 x2 x3 x4 -output xxx
复制代码
用MachOView
打开会看到通用二进制文件
由Fat Header
和四个可执行文件
组成
可执行文件
是由
Header
、
Load commands
和
Data
组成
通用二进制文件
看做四本翻译语言不一样的书,每本书有
标题(header)
、
目录(load commands)
、
内容(data)
另外咱们也能够经过otool
命令行查看MachO文件结构
$ otool -f universe
复制代码
header
包含了该二进制文件的字节顺序、架构类型、加载指令的数量等,使得能够快速确认一些信息,好比当前文件用于32 位
仍是64 位
,对应的处理器是什么、文件类型是什么
Xcode中 shift+command+O
->load.h
->以下信息
struct mach_header_64 {
uint32_t magic; /* 魔数,快速定位64位/32位 */
cpu_type_t cputype; /* cpu 类型 好比 ARM */
cpu_subtype_t cpusubtype; /* cpu 具体类型 好比arm64 , armv7 */
uint32_t filetype; /* 文件类型 例如可执行文件 .. */
uint32_t ncmds; /* load commands 加载命令条数 */
uint32_t sizeofcmds; /* load commands 加载命令大小*/
uint32_t flags; /* 标志位标识二进制文件支持的功能 , 主要是和系统加载、连接有关*/
uint32_t reserved; /* reserved , 保留字段 */
};
复制代码
mach_header_64(64位)对比mach_header(32位)只多了一个保留字段
load commands
是一张包括区域的位置、符号表、动态符号表等内容的表。 它详细保存着加载指令的内容,告诉连接器如何去加载这个 Mach-O 文件。 经过查看内存地址咱们发现,在内存中load commands
是紧跟在header
以后的
名称 | 内容 |
---|---|
LC_SEGMENT_64 | 将文件中(32位或64位)的段映射到进程地址空间中 |
LC_DYLD_INFO_ONLY | 动态连接相关信息 |
LC_SYMTAB | 符号地址 |
LC_DYSYMTAB | 动态连接相关信息 |
LC_LOAD_DYLINKER | 动态连接相关信息 |
LC_UUID | 动态连接相关信息 |
LC_VERSION_MIN_MACOSX | 支持最低的操做系统版本 |
LC_SOURCE_VERSION | 源代码版本 |
LC_MAIN | 设置程序主线程的入口地址和栈大小 |
LC_LOAD_DYLIB | 依赖库的路径,包含三方库 |
LC_FUNCTION_STARTS | 函数起始地址表 |
LC_CODE_SIGNATURE | 代码签名 |
data
是MachO文件中最大的部分,其中_TEXT段
、_DATA段
能给到不少信息
load commands
和data
之间还留有很多空间,给咱们留下了注入代码的冲破口
名称 | 做用 |
---|---|
_text | 主程序代码 |
_stubs、_stub_helper | 动态连接 |
_objc_methodname | 方法名称 |
_objc_classname | 类名称 |
_objc_methtype | 方法类型(v@:) |
_cstring | 静态字符串常量 |
_DATA段
名称 | 做用 |
---|---|
_got=>Non-Lazy Symbol Pointers | 非懒加载符号表 |
_la_symbol_ptr=>Lazy Symbol Pointers | 懒加载符号表 |
_objc_classlist | 方法名称 |
... | ... |
dyld(the dynamic link editor)是苹果的动态连接器,是苹果操做系统的一个重要组成部分,在系统内容作好程序准备工做以后,交由dyld负责余下的工做
系统库的方法因为是公用的,存放在共享缓存中,那么咱们的MachO在调用系统方法时,dyld会将MachO里调用存放在共享缓存中的方法进行符号绑定。这个符号在release环境
是会被自动去掉的,这也是咱们常用收集 bug 工具时须要恢复符号表的缘由
以上内容了解便可