持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情
前言
- 对symbol table 的symbol的理解(public symbol 、private symbol 、stripped symbol)
- Mach-O 初识
- hook方式汇总
I 对symbol的理解
1.1 什么是symbol?
计算机中,一个函数的指令被存放在一段内存中,当进程需要执行这个函数的时候,它必须知道要去内存的哪个地方找到这个函数,然后执行它的指令。
也就是说,进程要根据这个函数的名称,找到它在内存中的地址,而这个名称与地址的映射关系,是存储在 “symbol table”中。 “symbol table”中的
symbol
就是这个函数的名称, 进程会根据这个symbol
找到它在内存中的地址,然后跳转过去执行。
symbol 跟函数名不同。
1.2 symbol的分类
为了避免其他app利用symbol,执行其他app库的函数symbol 被分为2类
public symbol 和private symbol 第三类 stripped symbol :
symbol的来源: symbol通常由 IDA 对二进制文件的分析结果中提取。
II MSHookFunction 和 MSFindSymbol
2.1 MSHookFunction
MSHookFunction 作用于C 和C++函数通过编写汇编指令,在进行执行到 function 时 转而执行 replacement,同时保存在 function 的指令及其返回地址,使得用户可以选择性的执行 function ,并保证进程能够在执行完 replacement 后继续正常运行。
CydiaSubstrate(由MobileHooker、 MobileLoader 、Safe mode组成) 是对MSHookMessageEx进行封装。
iOS 的底层是用 C C++ 实现的,编译之后生成的大都是 subroutine, class-dump 拿它没办法,只能使用IDA 工具。——- 因此在OC 开发中使用C 语言实现算法相关的功能,代码更具安全性。
2.2 MSFindSymbol
MSHookFunction 直接作用private symbol是无效的,因此saurik 提供 MSFindSymbol 的 API 来访问private symbol。
void *MSFindSymbol(MSImageRef image, const char *name);
MSImageRef image;
image = MSGetImageByName("/usr/lib/libSystem.B.dylib");
void *(*palloc)(size_t);
palloc = (void *(*)(size_t)) MSFindSymbol(image, "_malloc");
void *data = (*palloc)(1024);
free(data);
III Mach-O
3.1 文件类型:
- Executable: 应用的主要二进制
- Dylib: 动态链接库(又称 DSO 或 DLL)
- Bundle: 不能被链接的 Dylib,只能在运行时使用 dlopen() 加载,可当做 macOS 的插件。
- Image: executable,dylib 或 bundle
- Framework: 包含 Dylib 以及资源文件和头文件的文件夹
3.2 Mach-O 镜像文件
iOS 可执行文件是 Mach-O 格式,主要由 Header、Load Commands、Data 三部分
Header 头部
,包含可以执行的CPU架构,比如x86,arm64Load commands 加载命令
,包含文件的组织架构和在虚拟内存中的布局方式Data数据
,存储了实际的内容,主要是程序的指令和数据,它们的排布完全依照 Load Commands 的描述. 包含load commands中需要的各个段(segment)的数据
Mach-O 文件中的 Data 部分主要是以 Segment(段)和 Section (节)的方式来组织内容的, 被划分成一些 segement,每个 segement 又被划分成一些 section。
-
segment 的名字都是大写的,
且空间大小为页的整数
。页的大小跟硬件有关,在 arm64 架构一页是 16KB,其余为 4KB。 -
section 虽然没有整数倍页大小的限制,但是 section 之间不会有重叠。
3.3 几乎所有 Mach-O 都包含这三个segment(支持用户自定义Segment)
__TEXT,__DATA 和 __LINKEDIT
- __TEXT 代码段,只读可执行(r-x)
被执行的代码包括函数,和只读的字符串,类似__TEXT,__text的都是代码段 、包含 Mach header
- __DATA 数据段,包括可读写的全局变量、静态变量
类似中的__DATA,__data都是数据段 可读写(rw-)
- __LINKEDIT :包含启动 App 需要的信息【方法和变量的
元数据(位置,偏移量)
】(比如函数的名称、bind & rebase地址)以及代码签名、符号表等信息。
只读(r–)
有关段的概念可参考苹果官方文档 《OS X ABI Mach-O File Format Reference》:
3.4 ASLR地址空间布局随机化
- Address Space Layout Randomization 地址空间布局随机化,镜像会在随机的地址上加载。这其实是一二十年前的旧技术了。
3.5 代码签名
可能我们认为 Xcode 会把整个文件都做加密 hash 并用做数字签名。
其实为了在运行时验证 Mach-O 文件的签名,并不是每次重复读入整个文件,而是把每页内容都生成一个单独的加密散列值,并存储在 __LINKEDIT 中。这使得文件每页的内容都能及时被校验确并保不被篡改。
IV hook 的方式
【hook 的方式】一个是通过修改内存中懒加载和非懒加载符号表指针所指向的地址来达到修改方法的目的,作用于主模块懒加载和非懒加载表的符号。一个是 cydia substrate