iOS逆向与安全 - 5. Mach-O文件格式
前言
- Mach-O文件格式源码
- Mach-O苹果官方手册
想要程序跑起来,那么这个可执行文件的格式就需要被当前的操作系统所理解,比如:
- Linux 操作系统下可执行文件格式是 ELF
- Windows 的可执行文件格式是 PE32/PE32+
- Android 的可执行文件格式是 ELF
- OSX 和 iOS 的可执行文件格式是
Mach-O
准备工具
方式1: 终端查看
来到Mach-O文件所在位置,输入相关命令得到Mach-O文件信息。为了更直观点,推荐方式2查看Mach-O文件。
方式2: 工具查看
首先要下载一个可以查看Mach-O文件格式的工具,本来想用 MachOView ,无奈下载完后打开Mach-O文件后,会闪退,就去逆向论坛找了个大神些的替代MachOView的工具 MachOExplorer 。我这里下载使用的是MachOExplorer,下载完后,打开,点击菜单栏的 file -> Mach-O文件 (此处我用模拟器的运行,打开了Debug-iphonesimulator文件夹,找到ipa,邮件显示包内容后可以获得可执行文件)。
Mach-O文件是什么
在OSX和iOS系统下,平时接触到的可执行文件、库文件、dsym文件、动态库、动态链接器(dyld)都是这种格式。Mach-O的组成结构包括:Header
(头部)、Load commands
(加载命令)、Data
(Data包含多个 Segment
(段),Segment中包含多个 Section
(节))
简单介绍dsym文件,后续开篇介绍。
- dSYM 文件是什么: Xcode编译项目后,会有一个项目同名的 dSYM 文件,dSYM 是保存 16 进制函数地址映射信息的中转文件。
- dSYM 文件的作用: release 模式打包或上线后,崩溃错误不直观,这时就需要分析 crash report 文件,iOS 设备中会有日志文件保存我们每个应用出错的函数内存地址,通过 Xcode 的 Organizer 可以将 iOS 设备中的 DeviceLog 导出成 crash 文件,这个时候我们就可以通过出错的函数地址去查询 dSYM 文件中程序对应的函数名和文件名。大前提是我们需要有软件版本对应的 dSYM 文件,这也是为什么我们很有必要保存每个发布版本的 Archives 文件了。
Header (头部)
header的数据结构
Mach-O的头部信息,可以使我们快速得到一些信息,比如
32位结构还是64位结构,比如文件类型架构类型等等。
让我们先来看看header的数据结构定义。
/** 32位架构对于header的定义*/
struct mach_header {uint32_t magic; /* mach magic number identifier */cpu_type_t cputype; /* cpu specifier */cpu_subtype_t cpusubtype; /* machine specifier */uint32_t filetype; /* type of file */uint32_t ncmds; /* number of load commands */uint32_t sizeofcmds; /* the size of all the load commands */uint32_t flags; /* flags */
};/** 64位架构对于header的定义*/
struct mach_header_64 {uint32_t magic; /* mach magic number identifier */cpu_type_t cputype; /* cpu specifier */cpu_subtype_t cpusubtype; /* machine specifier */uint32_t filetype; /* type of file */uint32_t ncmds; /* number of load commands */uint32_t sizeofcmds; /* the size of all the load commands */uint32_t flags; /* flags */uint32_t reserved; /* reserved */
};
32位和64位架构的头文件对比,多了一个reserved(保留字段)。
现在来解释说明一下这些字段都有什么意义:
- magic : 魔数,用于快速确认该文件是64位还是32位的。若值为0xfeedfacf是64位的,值为0xfeedface则是32位的。
- cputype :CPU架构类型。比如arm,例如x86_64
- cpusubtype : 对应的架构具体类型。比如arm64、armv7等。
- filetype : 文件类型。比如可执行文件(MH_EXECUTE)、库文件、Dsym文件等。
- ncmds : 加载命令条数。
- sizeofcmds : 所有加载命令大小。
- flags : dyld加载时需要的标志位。
- reserved :保留字段。
/* filetype 类型 */
#define MH_OBJECT 0x1 /* relocatable object file */
#define MH_EXECUTE 0x2 /* demand paged executable file */
#define MH_FVMLIB 0x3 /* fixed VM shared library file */
#define MH_CORE 0x4 /* core file */
#define MH_PRELOAD 0x5 /* preloaded executable file */
#define MH_DYLIB 0x6 /* dynamically bound shared library */
#define MH_DYLINKER 0x7 /* dynamic link editor */
#define MH_BUNDLE 0x8 /* dynamically bound bundle file */
#define MH_DYLIB_STUB 0x9 /* shared library stub for static */
#define MH_DSYM 0xa /* companion file with only debug */
#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts *//* flags : dyld加载时需要的标志位。*/
#define MH_NOUNDEFS 0x1 // 目前没有未定义的符号,不存在链接依赖
#define MH_DYLDLINK 0x4 // 该文件是dyld的输入文件,无法被再次静态链接
#define MH_PIE 0x200000 // 加载程序在随机的地址空间,只在 MH_EXECUTE中使用
#define MH_TWOLEVEL 0x80 // 二级名称空间
dyld
动态链接器,苹果的开源项目, 下载dyld ,当内核执行到 LC_DYLINK
(后文讲述)的时候,链接器会启动,查找进程所依赖的动态库,并加载到内存中。
flags : MH_PIE - 随机地址空间(ASLR)
进程每一次启动,地址空间都会随机化。如果采用传统的方式,程序每启动一次,启动的虚拟内存镜像一致的话,黑客很容易就重写内存来破解程序。所以,ASLR可以有效避免黑客的攻击。
打开Xcode,来到Main函数,打断点,运行程序开启lldb调试。当到达断点位置时,在控制台输入:
/** 加载模块地址*/
image list -o -f
可以发现每次运行程序,地址都在变化。
flags : MH_TWOLEVEL - 二级名称空间
这是dyld的一个独有特性,说是符号空间中还包括所在库的信息,这样子就可以让两个不同的库导出相同的符号,与其对应的是平摊名称空间.
演示查看header结构
方式1: 通过命令行来查看Mach-O文件的header结构
/* file + 可执行文件路径 : 查看文件类型 */
zhuangyuan$ file GV_VOUCHER_CN
-> Mach-O 64-bit executable x86_64/* lipo -info + 可执行文件路径 : 查看文件架构 */
zhuangyuan$ lipo -info GV_VOUCHER_CN
-> Non-fat file: GV_VOUCHER_CN is architecture: x86_64/* otool -h + 可执行文件路径 : 查看Mach-O文件的header信息 */
zhuangyuan$ otool -h GV_VOUCHER_CN
->
Mach headermagic cputype cpusubtype caps filetype ncmds sizeofcmds flags0xfeedfacf 16777223 3 0x00 2 51 6184 0x00218085/* otool -hv + 可执行文件路径 : 查看Mach-O文件的header信息的翻译*/
zhuangyuan$ otool -hv GV_VOUCHER_CN
->
Mach headermagic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 X86_64 ALL 0x00 EXECUTE 51 6184 NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE
如下图:
方式2: 利用MachOExplorer工具查看Mach-O文件的header结构
比终端看的更直观看,终端的好处就是装逼还挺成功的,哈哈。
Load commands 结构 (加载指令模块)
Load commands 紧跟在header之后,说明了操作系统应当如何加载文件中的数据,对系统内核加载器和动态链接器起了指导性作用。这些加载指令告诉加载器
如何处理二进制数据,有些命令是由内核处理的,有些是由动态链接器处理的。在源码中有明显的注释说明这些是动态链接器处理的。
Load commands
struct load_command {uint32_t cmd; /* type of load command */uint32_t cmdsize; /* total size of command in bytes */
};
- cmd: 加载指令类型
- cmdsize :加载指令大小
查看Mach-O文件的所有数据
方式1: 终端 - 演示查看load commands结构
终端输入:
otool -lv + 文件
方式2: 工具查看
Segments
Mach-O文件有多个段(Segment),每个段有不同的功能,一般的段又会按不同的功能划分为几个区(Section)。
Segments数据结构
/*segment_command_64 数据结构,其他段的数据结构类似,感兴趣可以去阅读源码*/
struct segment_command_64 { /* for 64-bit architectures */uint32_t cmd; /* LC_SEGMENT_64 */uint32_t cmdsize; /* includes sizeof section_64 structs */char segname[16]; /* segment name */uint64_t vmaddr; /* memory address of this segment */uint64_t vmsize; /* memory size of this segment */uint64_t fileoff; /* file offset of this segment */uint64_t filesize; /* amount to map from the file */vm_prot_t maxprot; /* maximum VM protection */vm_prot_t initprot; /* initial VM protection */uint32_t nsects; /* number of sections in segment */uint32_t flags; /* flags */
};
Segments结构字段说明
LC_SEGMENT
和 LC_SEGMENT_64
是加载的主要命令,负责指导内核将文件中(32位或64位)的段映射到进程的地址(内存)空间中。
- cmd : 即 Load commands 的类型,比如
LC_SEGMENT_64
代表将文件中64位的段映射到进程的地址空间。还有LC_SEGMENT、LC_DYLD_INFO_ONLY等等类型。 - cmdsize : 代表当前 ‘load command’ 的大小
- VM Address :段的虚拟内存地址
- VM Size : 段的虚拟内存大小
- file offset: 段在Mach-O文件中的偏移量
- file size : 段在文件中的大小
- nsects : 标识了Segment中有多少section
- segname[16] : 段的名称。例如__PAGEZERO、__TEXT等等。
将段对应的文件内容加载到内存中的流程:
从file offset处 加载 file size 大小到 虚拟内存VM Address处
。如果当前段是LC_SEGMENT_64(__PAGEZERO) ,则这个段的file offset、file size 、VM Address为0,因为这个段不具备访问权限,用来处理空指针的。
具体段说明
- LC_SEGMENT_64(__PAGEZERO) : 空指针陷阱段,映射到虚拟内存空间的第一页,用于捕捉对NULL指针的引用。
- LC_SEGMENT_64(__TEXT) : 包含了
执行代码
以及其他只读数据
。该段数据的保护级别为:VM_PROT_READ(读)、VM_PROT_EXECUTE(执行),防止内存中被修改。 - LC_SEGMENT_64(__DATA) : 包含了程序数据,可读/可写数据存放段。
- LC_SEGMENT_64(__LINKEDIT) : 链接器使用的符号以及其他表,链接的部分,支持dyld,包含了一些符号表等数据。
- LC_SYMTAB : 符号表信息
- LC_DYSYMTAB :动态符号表信息
- LC_LOAD_DYLINKER : 加载动态链接器(/usr/lib/dyld),使用Mach-O文件的时候链接器,可以看到name为 /usr/lib/dyld 的链接器来加载Mach-O文件。
- LC_UUID : 对每个Mach-O文件都是唯一标识,crash解析中也会有,去匹配dysm文件和crash文件。
- LC_VERSION_MIN_IPHONEOS : 二进制文件要求的最低操作系统版本(iOS Deployment Target) ,打开xcode ,输入iOS Development Target 可以查看版本
- LC_MAIN : 设置程序主线程的入口地址和栈大小
- LC_ENCRYPTION_INFO : 加密信息,查看文件是否加密(在终端输入
otool -l 文件名 | grep cryptid
) - LC_LOAD_DYLIB : 加载的动态库,包括动态库地址和名称,当前版本号,兼容版本号(终端输入`otool -l 文件名)
- LC_RPATH : 环境变量路径
- LC_FUNCTION_STARTS : 函数起始地址表
- LC_CODE_SIGNATURE : 记录可执行文件的代码是否签名
Section
大写的表示Segment,小写的表示section。
例如 __TEXT 和 __text.
Section数据结构
struct section { /* for 32-bit architectures */char sectname[16]; /* name of this section */char segname[16]; /* segment this section goes in */uint32_t addr; /* memory address of this section */uint32_t size; /* size in bytes of this section */uint32_t offset; /* file offset of this section */uint32_t align; /* section alignment (power of 2) */uint32_t reloff; /* file offset of relocation entries */uint32_t nreloc; /* number of relocation entries */uint32_t flags; /* flags (section type and attributes)*/uint32_t reserved1; /* reserved (for offset or index) */uint32_t reserved2; /* reserved (for count or sizeof) */
};
结构字段说明
- sectname:比如_text、stubs
- segname :该section所属的segment,比如__TEXT
- addr : 该section在内存的起始位置
- size: 该section的大小
- offset: 该section的文件偏移
- align :字节大小对齐
- reloff :重定位入口的文件偏移
- nreloc: 需要重定位的入口数量
- flags:包含section的type和attributes
主要的节说明
- __text:主程序代码
- __stub_helper :用于动态链接器的存根
- __symbolstub1 : 用于动态链接器的存根
- __objc_methname :OC的方法名
- __objc_classname : OC的类名
- __cstring : 字符串
查看__text 节的全部内容(二进制)
otool -s __TEXT __text + 文件
查看__text 节的全部内容(汇编)
查看__text 节的内容前10条数据(汇编)
利用MachOExplorer工具
演示部分
Mach-O文件开始加载的地方
- 打开MachOExplorer查看__TEXT部分的虚拟地址0x100000000
- 打开xcode 来到main函数打断点 ,输入
image list -o -f
查看模块加载的地址,可以看到加载可执行文件的基地址 0x000fabcd - 在控制台输入
p/x 0x000fabcd + 0x100000000
得到了一个新的地址$0 - 选择xcode菜单的Debug —> debug workflow —> view memory 之后再Address里面输入$0地址,回车
- 可以看到Mach-O文件格式的一些数据 ,所以0x100000000就是Mach-O文件加载开始的地方.
本文参考了的文章:
趣探 Mach-O:文件格式分析
感谢。
iOS逆向与安全 - 5. Mach-O文件格式相关推荐
- iOS逆向之深入解析MachO文件
MachO文件简介 一.什么是MachO文件? Mach-O其实是Mach Object文件格式的缩写,它是Mac以及iOS上一种用于可执行文件.目标代码.动态库的文件格式,类似于Windows上面的 ...
- iOS逆向(1)——利用ipa重签名,3分钟iPhone安装多个微信
本文要达成如图效果,在一台iPhone上安装第二个微信: 准备: Xcode 微信ipa(可通过iTool进行下载) 重签名脚本 步骤 打开Xcode,新建Single View App项目,名字可以 ...
- android r 编译找不到头文件_「投稿」iOS逆向——砸壳与反编译
作者:疯狂的蛋神 近来对iOS逆向十分感兴趣,就在业余时间里自己在上网找了各种资料学习,发现许多资料对于一些细节描述的不够详细,所以也踩了很多坑,我也将自己踩的一些坑总结出来,希望对大家有所帮助. 注 ...
- iOS逆向之自动化重签名
iOS逆向之自动化重签名 准备工作 非越狱的iPhone手机 用PP助手下载: 微信6.6.5(越狱应用) 步骤 新建工程"自动化签名",在工程目录下新建APP文件夹放置需要重签名 ...
- iOS 逆向 - 收藏集 - 掘金
分分钟让你在 微信运动 霸占榜首 - iOS - 掘金 为了纪念我失去的已越狱iPad, 不得不写点什么. 所以...以下内容 不需要越狱. 微信运动 6万步是什么概念,我不知道,因为我没走过,不过有 ...
- IOS 逆向开发(一)密码学 非对称加密RSA
IOS 逆向开发(一)密码学 RSA 1. 密码学发展简介 2. 非对称加密RSA产生过程 3. RSA 数学原理 3.1 离散对数问题 3.1.1 原根 3.2 欧拉函数Φ 3.3 欧拉定理 3.4 ...
- android微信逆向工程,iOS逆向 - 微信自动添加好友
相关源码:Github地址 一.前言 本篇主要实现在微信上自动添加好友,从而熟悉 iOS 逆向分析的过程. 二. 工具 2.1 MacBook 软件 制作 Tweak 的工具 端口转发,可以让我们通过 ...
- iOS逆向-微信自动添加好友
前言 上次完成了 macOS 版微信小助手,现在终于有(xian)时(de)间(huang)来说说 iOS 逆向了.本篇主要实现在微信上自动添加好友(即自动验证新的朋友申请),从而熟悉 iOS 逆向分 ...
- IOS逆向(1)IOS越狱
前段时间学习完JS逆向后,准备入门IOS逆向了.打算写在博客中记录下学习的过程,也会把踩过的坑记录下来让大家一起交流学习.JS逆向相关的基础网上比比皆是,后续会分享一些关于JS逆向相关的项目,就不从基 ...
- 【iOS逆向与安全】iOS插件开发光速入门
前言 经过之前的学习,相信你已经能熟练的使用Frida-trace.IDA Pro等逆向工具.不过,仅仅到这肯定是不够的.接下来,学会把你逆向的结果打包成插件并运行,那iOS逆向,你也就真正的入门了. ...
最新文章
- Springboot使用bean方式详解(附代码)
- 【学术相关】研究生、博士生全程只靠自己能否发一篇 SCI?
- Java黑皮书课后题第8章:8.29(相同的数组)如果两个二维数组m1和m2具有相同的内容,则它们是相同的。编写一个方法,如果m1和m2相同的话,返回true
- (原創) 如何讀取/寫入文字檔? (IC Design) (Verilog)
- UVAoj 348 - Optimal Array Multiplication Sequence
- Redis4.0.13 安装踩雷记录
- 北鼎机器人_北鼎T752已入手,我的感受
- 【Unity3D开发小游戏】Unity3D开发《3D迷宫》小游戏
- 小蜜蜂吉他谱 高八度和低八度
- matlab 根轨迹 系统单位阶跃响应,二阶系统单位阶跃响应MATLAB仿真设计.doc
- MATHTYPE安装出现问题:无法打开要写入的文件;MathType打开word时“安全警告,宏已被禁用”;mathtype与AXmath不能同时使用
- ZZULIOJ-1088: 手机短号 (多实例)(Java)
- 有时用weblogic用户启动weblogic时会报错的原因以及解决办法
- 在线教育软件开发的目的是什么?
- QT的firstblood
- 关于TPR,FPR,precision,accuracy,F1
- java整合谷歌翻译
- 简单的学生成绩查询web系统
- 基于GCCAVR的诺基亚5110液晶显示
- Cantor三分集为啥不能在Myeclipse上完美实现呢?
热门文章
- h5手机端适配字体设置
- Win11 22H2更新了什么?Win11 22H2更新内容大盘点
- 人工智能“军备竞赛”的真正危险是什么?专家警告:未来挺可怕!
- 一条网线怎样既接路由器又接电视?
- android扣扣登录界面,手机QQ
- java php bridge吧_使用Php-Java Bridge
- 魅族关掉 android beam,科普Android Beam功能介绍及红米Note2与魅族魅蓝no
- 【天命奇御】成就进度62/71的通关攻略(4·地图篇)
- 银行业务学习之道:银行帐号、卡号和客户号分析
- 浅谈linux的inode