[TOC]
回顾
注入的相关要素:
- 注入的形式:利用动态库的特性进行注入,包括Framework、Dylib。可以修改二进制文件,但是过于麻烦。
- 注入的步骤:
- 将动态库注入进APP(配置工程cope file,让工程和动态库进行关联)
- 修改MachO文件中的Load Commands段,使用yololib工具进行修改,
- 在动态库中添加自己代码。
- 注入的大致原理:APP在启动时会根据Load Commands段对依赖的库进行加载,在被加载的库中进行hook等操作。
HOOK概述
iOS中hook的几种方式:
1、Method Swizzle
利用runtime特性进行hook
2、fishhook
利用MachO文件加载原理,通过修改懒加载和非懒加载两个表的指针达到C函数HOOK的目的。
C函数部分是动态的,部分是静态。非自己APP中的函数都是动态加载到内存中的,这部分属于动态C函数。而自己当前APP的函数在编译时就指定了,不能被修改。
3、Cydia Substrate
通过动态库形式注入如到APP中,因此手机无需越狱。
Cydia Substrate主要由3部分组成
- MobileHooker
- MSHookMessageEx 主要作用于Objective-C方法,用于钩消息。
- MSHookFunction 主要作用于C和C++函数。
- MobileLoader
用于加载第三方dylib在运行的应用程序中。
- safe mode
CydiaSubstrate引入了安全模式,在安全模 式下所有基于CydiaSubstratede 的三方dylib都会被禁用,便于查错与修复
fishhook原理
fishhook简单使用
钩函数,系统函数NSLog()。
- 钩住系统函数NSLog();
- 钩不住APP内部的系统函数;
原理探究
大致原理
图:
fishhook所做的只能对外部的函数进行重绑定,而内部的函数是不能进行重绑定的。
需要了解APP加载到内存的流程、共享缓存区。
共享缓存中包含系统各种函数等内容,因为各系统版本的内容量大小不一致等原因造成共享区所在占用的内存大小也不一致。
macho在进行加密时Apple是对每个page进行加密,其中text 段的page是只读的,而data段的page是可读写的。
对符号表的设计是采用PIC(position independent code)技术的延伸,用动态绑定实现链接。
-
在生成app期间进行build,app内部的函数直接生成指向函数的地址,去除了函数名。而外部函数(如系统库、其他三方库中的函数)会在MachO文件的_Data中生成一个函数指针,以0补全;
在此创建的指针就是常说的符号,符号指向内部函数调用,外部函数地址。
APP运行前存放在磁盘上,需要通过dyld加载进内存中;
而iOS现在采用
ASLR
(address space layout random)技术使得app加载进内存时,macho所在的内存区域都不尽相同,采用偏移来查到;app加载进内存过程中dyld对指向外部函数的指针进行赋值(将具体系统库函数的地址存入指针),即进行动态绑定;
原理验证
- 通过MachO查找到NSLog在lazy_symbol表中的offset1;
- 使用image list 查看MachO相对于共享缓存区的偏移量offset0;
- offset0+offset1得到指向NSLog的指针在运行过程中的实际内存address;
- 通过使用
dis -s address
进行反汇编查看调用的函数; - rebinding后再次查看即可查看到address已经改变。
动态表的查找
待续
基础反hook
- 在自己工程内对method_exchange进行交换,交换成自己的函数,并在自己的函数调用原函数;
- 之后在使用自己交换后的函数进行使用;
- 但其他人通过method_exchang钩的时候会不成功;
- 另外还需要对runtime中的get/set_method方法进行反hook处理;
查看一个macho文件的动态加载表中的加载顺序,是否与工程设置有关,以及加载顺序是否与表中排序一致
反反hook
- 覆盖(同名)掉原有的反hook动态库,覆盖的动态库中不添加代码。
- 调整动态库的加载顺序,
关于指针
// 其实指针就是存放地址的变量?
int i = 1; // 存整型数据变量,在栈内存中用一个变量指向常量区内存空间
int *p = &i; // 存整型数据变量所在内存的地址,在栈内存中用一个变量指向栈内存中的一个变量的空间地址
int j = *p;
j++;
*p = j;
p = &j+1; // 移动四个字节空间赋值给p
NSLog(@"%d", *p);