iOS 私有 API 调用检测机制探讨
最近发现部分 App 以字符串拼接的方法调用私有 API,在提交 AppStore 审核后被发现打回修改的案例。
对于开发者提交的二进制文件,Apple 是如何检查出私有 API 的调用 ?本文尝试探讨可能的检测机制,以及每种机制的漏洞。
私有 API 调用方法1:直接调用法
[self _privateMethod];
私有 API 调用方法2:字符串拼接法
借助 Objective-C 语言的动态特性,在运行时用 performSelector
执行拼接的 selector 方法:
NSArray *parts = @[@"_priva", @"teMethod"];
NSString *selectorString = [parts componentsJoinedByString:@""];
[self performSelector:NSSelectorFromString(selectorString) withObject:nil];
私有 API 检测方法1:符号表检查
用 nm
、otool
等工具导出二进制包的函数符号表,以检查私有 API 的调用。
开源项目 iOS-private-api-checker 以这种方式实现了对私有 API 调用的检查。
然而这种方法的缺点是,无法检测字符串拼接方法的私有 API 调用。
私有 API 检测方法2:运行时分析
在审核人员运行 App 的同时,用 runtime 工具检测是否调用了私有 API。具体原理待补充。
这种方法的漏洞,当审核人员无法进入调用了私有 API 的功能时(通过后台下发配置文件控制功能入口),会有漏测的情况。
私有 API 检测方法3:静态代码分析
为检测字符串拼接法调用私有 API,受论文 [1] 启发,可以在对二进制文件反汇编结果的基础上,进行静态分析:
- 找出动态调用 API 方法如
performSelector:
,以及调用对象的类 - 检查参数,如果参数是拼接方法生成,推导求得拼接的结果
- 根据 1 2 判断是否调用了私有 API
以私有 API 调用方法2 的代码为例,用 Hopper 对其反汇编,得到伪代码:
void -[ViewController viewDidLoad](void * self, void * _cmd) {
r31 = r31 - 0x60;
*(r31 + 0x30) = r22;
*(0x40 + r31) = r21;
*(r31 + 0x40) = r20;
*(0x50 + r31) = r19;
*(r31 + 0x50) = r29;
*(0x60 + r31) = r30;
*(r31 + 0x28) = ___stack_chk_guard;
*(r31 + 0x8) = self;
*(r31 + 0x10) = 0x100008d38;
[[r31 + 0x8 super] viewDidLoad];
*(r31 + 0x18) = @"_private";
*(0x28 + r31) = @"Method";
r0 = [0x100008d28 arrayWithObjects:r31 + 0x18 count:0x2];
r0 = [r0 retain];
r20 = r0;
r0 = [r0 componentsJoinedByString:@""];
r0 = [r0 retain];
[self performSelector:NSSelectorFromString(r0) withObject:zero_extend_64(0x0)];
[r0 release];
[r20 release];
if (___stack_chk_guard != *(r31 + 0x28)) {
__stack_chk_fail();
}
return;
}
可以看出,伪代码有着充分的信息,可以进行静态分析推导,判断代码片段是否调用了私有 API。
然而这种方法也有漏洞,拼接的字符串由服务器下发,可以避开检查。
更多
欢迎大家补充,可以留言在 https://github.com/liuslevis/hexo/blob/master/source/_posts/ios-private-api-detection.md
引用
[1] Bergeron, Jean, et al. “Static analysis of binary code to isolate malicious behaviors.” Enabling Technologies: Infrastructure for Collaborative Enterprises, 1999.(WET ICE’99) Proceedings. IEEE 8th International Workshops on. IEEE, 1999. PDF
[2] 反汇编的利器 IDA 和 Hopper 的基本使用 Niyao https://niyaoyao.github.io/2017/01/18/Learning-Reverse-From-Today-D3/
- nyoj-----42一笔画问题
- hdu-------1081To The Max
- nyoj------170网络的可靠性
- HDUOJ-------1052Tian Ji -- The Horse Racing(田忌赛马)
- 初学Java之Pattern与Matcher类
- 初学java之StringBuffer类的常用方法
- 初学java之大数处理
- hdu---1024Max Sum Plus Plus(动态规划)
- Go语言异步服务器框架原理和实现
- nyoj------布线问题(kruscal+求最小值)
- nyoj-----127星际之门(一)
- nyoj------20吝啬的国度
- HDUOJ-------2493Timer(数学 2008北京现场赛H题)
- go sync.Mutex 设计思想与演化过程 (一)
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- python转化excel数字日期为标准日期操作
- thinkPHP框架通过Redis实现增删改查操作的方法详解
- PHP中引用类型和值类型功能与用法示例
- PHP文件上传小程序 适合初学者学习!
- php的扩展写法总结
- 实例介绍PHP删除数组中的重复元素
- Python迭代器协议及for循环工作机制详解
- PHP CURL中传递cookie的方法步骤
- PHP 结合 Boostrap 结合 js 实现学生列表删除编辑及搜索功能
- Yii2处理密码加密及验证的方法
- PHP实现获取ip地址的5种方法,以及插入用户登录日志操作示例
- python如何输出反斜杠
- 在Laravel5中正确设置文件权限的方法
- asp函数split()对应php函数explode()
- php获取目录下所有文件及目录(多种方法)(推荐)