iOS逆向 MachO文件

欢迎阅读iOS逆向系列(按序阅读食用效果更加)缓存

写在前面

以前在iOS逆向系列中屡次提到MachO,本文将带着你们一探究竟bash

工具:MachOView 密码:y2wr微信

1、MachO初探

1.定义

MachO实际上是Mach Object文件格式的缩写,是mac以及iOS上可执行文件的格式,相似于Windows上的PE格式(Portable Executable)、Linux上的elf格式(Executable and Linking Format)架构

它是一种用于可执行文件、目标代码、动态库的文件格式,做为.out格式的替代,MachO提供了更强的扩展性app

2.常见的MachO文件

  • 目标文件.o
  • 库文件
    • .a
    • .dylib
    • .Framework
  • 可执行文件
  • dyld(动态连接器)
  • .dsym(符号表:Relese环境运行生成)

3.查看文件类型

$ file xxx.xx 函数

2、关于架构

1.架构表

其实iPhone不一样的型号对应的架构是不同的工具

架构 手机型号
i386 32位模拟器
x86_64 64位模拟器
armv7 iPhone四、iPhone4S
armv7s iPhone五、iPhone5C
arm64 iPhone5s——iPhoneX
arm64e iPhone XS、iPhone XS Max、iPhoneXR、iPhone11...

2.生成多种架构

新建一个工程,真机运行,查看可执行文件仅仅是一个arm64架构的 post

将项目最低适配系统调为iOS9.0,真机运行 Relese环境

为何要改成iOS9.0呢?是由于iPhone5c等armv七、armv7s架构不支持iOS11.0性能

为何要Relese环境运行呢?由于Xcode默认Debug只生成单一架构 ui

怎么生成全部架构?Xcode10中只包含了v7和64,须要在Architectures中添加

3、通用二进制文件

1.定义

通用二进制文件(Universal binary)也被叫作胖二进制(Fat binary)

  • 苹果公司提出的一种程序代码,能同时适用多种架构的二进制文件
  • 同一个程序包中同时为多种架构提供最理想的性能
  • 由于须要储存多种代码,通用二进制应用程序一般比单一平台二进制的程序要大
  • 可是因为两种架构有共通的非执行资源,因此并不会达到单一版本的两倍之多
  • 并且因为执行中只调用一部分代码,运行起来也不须要额外的内存

2.拆分/合并架构

架构拆分

合并架构

通用二进制大小为342kb,四个架构大小为80+80+80+81=321kb

What!为何不是单纯的1+1=2?

由于不一样架构之间代码部分是不共用的 (由于代码的二进制文件不一样的组合在不一样的 cpu 上可能会是不一样的意义),而公共资源文件是公用的

利用上述方法能够给咱们的app瘦身

结论:

胖二进制拆分后再重组会获得原始胖二进制

通用二进制的大小可能大于子架构大小之和,也可能小于,也可能等于,取决于公共资源文件的多少

3.终端命令行

// 查看二进制文件
$ lipo -info xx 
// 通用二进制文件
// 拆分二进制文件
lipo xxx -thin armv7 -output xxx
// 组合二进制文件
lipo -create x1 x2 x3 x4 -output xxx
复制代码

4、MachO文件

1.总体结构

MachOView打开会看到通用二进制文件Fat Header四个可执行文件组成

可执行文件是由 HeaderLoad commandsData组成
咱们能够这么理解,把 通用二进制文件看做四本翻译语言不一样的书,每本书有 标题(header)目录(load commands)内容(data)

  • header:
  • load commands:
  • data:

另外咱们也能够经过otool命令行查看MachO文件结构

$ otool -f universe
复制代码

2.header

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位)只多了一个保留字段

3.load commands

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 代码签名

4.data

data是MachO文件中最大的部分,其中_TEXT段_DATA段能给到不少信息

load commandsdata之间还留有很多空间,给咱们留下了注入代码的冲破口

_TEXT段

名称 做用
_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 方法名称
... ...

5、dyld

dyld(the dynamic link editor)是苹果的动态连接器,是苹果操做系统的一个重要组成部分,在系统内容作好程序准备工做以后,交由dyld负责余下的工做

系统库的方法因为是公用的,存放在共享缓存中,那么咱们的MachO在调用系统方法时,dyld会将MachO里调用存放在共享缓存中的方法进行符号绑定。这个符号在release环境 是会被自动去掉的,这也是咱们常用收集 bug 工具时须要恢复符号表的缘由

写在后面

以上内容了解便可

相关文章
相关标签/搜索