最近我的好友遇到一个问题,他上线 iOS 项目的时候由于被查到使用私用 API 被拒。利用这次机会给大家普及一下利用逆向的思维定位私有 API 所在的位置。
X同学:“素燕,忙吗?请教一个问题。「刚接手」了个项目,最近上线的时候,苹果说我使用了私有 API,但是我在项目中根本找不到这个私有 API。但是我用 grep 命令确实能找到这个 api,如何才能定位到这个 API 在哪个类里使用吗?”。
为了确认他给我描述的问题确实是他要解决的问题,我说道:“我看看苹果给你发的被拒内容”。
拿到被拒的内容如下:
Your app uses the "prefs:root=" non-public URL scheme, which is a private entity. The use of non-public APIs is not permitted on the App Store because it can lead to a poor user experience should these APIs change.
Specifically, your app uses the following non-public URL scheme:
prefs:root=notifications_id
Continuing to use or conceal non-public APIs in future submissions of this app may result in the termination of your Apple Developer account, as well as removal of all associated apps from the App Store.
这个被拒消息我以前也遇到过,解决办法就是在项目中搜索 prefs:root 这个字符串,然后替换成非私有 API,但是他在项目中并没有找到这个字符串。通过 X同学描述的信息可知,目前已经在项目中查找了字符串 prefs:root=notifications_id ,也用 grep 命令查找到确实使用了这个 API。 说明网上已经找不到解决方案了。
因为最近很忙,索性中午不休息了,帮他看看这个问题。我说道:“给我一个 ipa 包,我看看吧”。
拿到 ipa 包后,从 ipa 包中找到可执行文件(Mach-O),拖到 Hopper Disassembler 这个工具中(以下简称 Hopper)。Hopper 是逆向使用比较多的工具,它可以通过二进制文件反汇编成汇编代码,支持 Objective-C。
Hopper Disassembler, the reverse engineering tool that lets you disassemble, decompile and debug your applications.
https://www.hopperapp.com/
等 Hopper 分析完成后,我们开始搜索字符串 prefs:root=notifications_id 。发现在下图这个位置:
双击进行调转到具体实现的地方,红框中使用这个字符串的地方:
既然找到了使用的函数,在本图的最顶端,可以看到这段函数的入口地址(第一个红框的位置):
双击这个地址可以定位到具体的类。发现在 YLKBluetoohDeviceListVC 这个类中。到目前为止,类名和具体的函数都找到了:
我们可以看一下这个函数的大体逻辑,从图中可以看出调用了 openURL 这个方法,这个方法会跳转到苹果系统的某个位置,比如跳转到设置里,后来被苹果当做了私钥 API(指 prefs:root 这种方式):
定位到具体位置后,我让 X同学到项目中查找一下这个方法的源码。不一会他发来了:
NSData *encryptString = [[NSData alloc] initWithBytes:(unsigned char []){
0x70,0x72,0x65,0x66,0x73,0x3a,0x72,0x6f,0x6f,0x74,0x3d,
0x4e,0x4f,0x54,0x49,0x46,0x49,0x43,0x41,0x54,0x49,0x4f,
0x4e,0x53,0x5f,0x49,0x44} length:27];
NSString *string = [[NSString alloc] initWithData:encryptString encoding:NSUTF8StringEncoding];
if (SYSTEM_VERSION_10) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:string] options:@{} completionHandler:nil];
} else {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:string]];
}
看完这段代码,我“喜极而泣”。难怪在项目中搜索不到 prefs:root=notifications_id 这个字符,原来他把这个字符串转换成了 16 进制,即使这样也没瞒过苹果。因为从可执行文件分析的结果来看,即使转换成 16 进制,但是在可执行文件中依然是字符串。如果你想通过“加密”的方式骗过苹果,请使用高级一点的方法。
至此,整个分析过程就完成了。这个过程省略了好多关于逆向的知识。如果你想找入门逆向的教程,可以参考(当年我写的比较详细):
https://github.com/lefex/iWeChat。
最近新出了一本逆向的书籍,推荐给大家!
当然也可以看这两本,都不错:
广告时间:
目前我正在写《前端小课》,帮助你从 0 到 1 入门前端,所有的内容都在“素燕”这个公众号中。了解前端小课:
我的2019 —我与《前端小课》
推荐阅读:
第六阶段 · 期待已久的 Vue