OC逆向12:Mach-O文件(下)
前言
本文主要介绍Mach-O的结构演示
Mach-O内部结构
因为Mach-O文件本身是一种文件格式,所以我们一定需要了解其文件内部结构,其内部结构如下图所示:
Mach-O
的组成结构主要分为 三部分
Header
包含该 二进制文件的一般信息- 字节顺序、结构类型、加载指令的数量等
- 使得可以快速确认一些信息,比如当前文件用于32位还是64位,对应的处理器是什么?文件类型是什么?
Load commands
(加载命令)一张包含很多内容的表- 内容包括
区域的位置、符号表、动态符号表
等
- 内容包括
Data
(数据)通常是对象文件中最大的部分- 包含
Segment
的具体数据
,首先是分段
,然后段中分节
- 包含
终端命令:otool
在终端中,我们通过 otool
查看Mach-O的一些指令
1 | % otool |
- 查看Mach-O的header信息:
otool -f Demo
1 | % cd /Users/zhangjian/Library/Developer/Xcode/DerivedData/Demo-edwjvapoqaffzeeiyzyhfryhfrsr/Build/Products/Release-iphoneos/Demo.app zhangjian@zhangjiandeMBP Demo.app % otool -f Demo |
MachOView 软件
首先 Show in finder 找到Demo.app程序包 -> 右键显示包内容 -> 找打exex可执行文件
将demo拖拽到 MachOView 查看 Mach-O 文件
- 验证 ARM-V7 与 ARM_V7S 之间是否是分页?
* ARM_V7 与 ARM_V7S 的差值:16384 + 79280 - 98304 = -2640
* ARM_V7 的大小:-2640 - 79280 = -81920,查看这个值是否 pageSize(4096)的倍数
* 是否是PageSize的倍数:91920/4096 = -20(MacOs中),但是由于是iOS,所以 20/4 = 5页,说明是分页了,即按页对齐
两者对比
- otool 与 MachOView 查看的Mach-O进行对比
MachOView演示
通过 MachOView
查看Mach-O结构,分为三部分:Header、Load Commands、Data
- 查看 arm64 下 Mach-O 的header
- 查看 Load Commands
* VM Addr:虚拟内存地址
* VM Size:虚拟内存大小,在运行时,在内存中的大小,4g
* 64位地址:0x12345678a2345678
* 32位地址:0x12345678
* File offset:数据在文件中偏移量
* File size:数据在文件中的大小
- Section 中分为两大类:
__TEST(代码)、__DATA(数据)
Header 的数据结构
- 在
CMD + shift + O
搜索loader.h
,找到Mach_Header_64
(arm64架构)的数据结构如下所示,与mach_header
相比,只是多了一个reverse
1 | // 1.mach_header |
查看filetype种类
- OC文件:
#define MH_OBJECT 0x1
- 可执行文件:
#define MH_EXECUTE 0x2
- …
- OC文件:
Load Commands
Load Commands 中的相关字段含义如下所示:
LC_SEGMENT_64
:将文件中(32位或64位)的段映射到进程地址空间中,主要分为__TEXT
、__DATA
、LINKEDIT
几大块LC_DYLD_INFO_ONLY
:动态链接相关信息LC_SYMTAB
:符号地址DYSYMTAB
:动态符号表地址LC_LOAD_DYLINKER
:使用谁加载,我们使用dyldLC_UUID:Mach
-O文件的唯一标识UUIDLC_VERSION_MIN_MACOSX
:支持最低的操作系统版本LC_SOURCE_VERSION
:源代码版本LC_MAIN
:设值程序主线程的入口地址和栈大小LC_ENCRYPTION_INFO_64
:加密信息LC_LOAD_DYLIB
:依赖库的路径,包含三方库LC_FUNCTION_STARTS
:函数起始地址表LC_CODE_SIGNATURE
:代码签名
演示
LC_SEGMENT_64
中__TEXT、__DATA、LINKERDIT
的对应关系如下图所示
- 查看 LC_DYLD_INFO_ONLY 动态链接信息
其中 Rebase 是重定向,重定向过程简述如下:
代码段
放入Mach-O文件,在编译时期,会生成一个偏移地址
在运行时期,
mach-o文件放入虚拟内存
,其内存也是随机变化的(由系统分配 -ASLR
)所以之前的代码段在mach-o中偏移值就不能使用了,需要通过
ASLR + Rebase Info Offset
重定向,主要改变的是汇编代码
- 查看
LC_SYMTAB
符号地址
- 查看
LC_LOAD_DYLINKER
,使用谁链接,这里使用的是dyld
- 查看 LC_UUID,mach-o文件识别的唯一标识
- 查看 LC_VERSION_MIN_MACOSX,支持的最低版本信息
- 查看 LC_SOURCE_VERSION,代码版本
- 查看 LC_MAIN,入口函数
作用:用于你想时找不到切入点时(例如:做了防护,运行就闪退),可以从这里找到
- 查看
LC_ENCRYPTION_INFO_64
,此时Crypt ID
为0
,表示还没有加密
Data
- 如果我们想快速定位代码段,需要通过
LC_SEGMENT_64(__TEXT)
中的VM Adress
- 查看 代码段 的 起始位置
也可以通过 objdump 命令来查看: objdump –macho -d Demo
从这里看出,正好与Mach-O文件中的对应
- 查看stub、stub_helper:主要是用于符号绑定,这里的
0x10006574
全是指向的00006574
偏移,且前面6句汇编都是在做符号绑定
- 查看外部符号表(即 调用外部函数,只有在运行时才绑定),有两个:懒加载、非懒加载
这里是先 绑定
专门 用来绑定外部的函数
,在用这个函数去绑定其他函数
总结
Mach-O 内部结构
header :用于快速确定该文件的CPU类型、文件类型
Load Commands:指示加载器如何设置并加载二进制数据
Data:存放数据,例如代码、数据、字符串常量、类、方法等。
- Section 中分为两大类:__TEXT(代码)、__DATA(数据)
可以通过
otool
命令查看Mach-O信息,例如查看header信息:otool -f Demo
可以通过
objump
命令来查看代码段:objump --macho -d Demo
- Post title:OC逆向12:Mach-O文件(下)
- Post author:张建
- Create time:2022-01-25 09:34:11
- Post link:https://redefine.ohevan.com/2022/01/25/OC逆向/OC逆向12:Mach-O文件(下)/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.