关于 IOS 私有库的搭建,⽹上的教程很少,目前为止,发现的⼀个⽐较好的⽂章,是教你私有库的搭建和扫描,但是⽂章因为存在时间⽐较⻓,套在现在框架中,难免有些不适⽤,我就在⼤神 (Deft_MKJing 宓珂璟) 的基础上,做⼀些补充和修改。在这⾥,我想感谢下⼤神的奉献和先驱者们的探索,我也把⾃⼰的经验分享出来,做⼀点贡献。

我之前出了一个提取 IOS Run-header 的文章,和这个文章相当于是系列文章,这篇文章主要是教大家怎么提取 document_apis, 也就是大神文章中集合 C。这里针对的是 IOS 15.0 版本。

回顾

我们先回顾下文章中说的集合 C 的创建,在 9.0 之前,Apple 的文档是以 docSet 的格式存在的,但是现在,Xcode 版本已经是 13.1 版本

SDK 在本机的路径为

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk

版本查看可以在路径下 SDKSettings.json 文件中看到

文章中关于 9.0 版本后,Xcode 9 之后的 API 内置在一个 Framework 里面,主要是两个文件:map.db 和 cache.db, 路径为:

/Applications/Xcode.app/Contents/SharedFrameworks/DNTDocumentationSupport.framework/Versions/A/Resources/external

那么问题就出来了,在我们最新的环境中,文档是好像是内嵌了个浏览器的形式展现的,同时,也找不到 map.db 文件,所以这里,我们需要调整下。
获取 document_apis 我目前总结了两种。lzfse 方法和 Dash 方式,我们先说 lzfse 的方式,再说,Dash 的方式就比较容易理解。并且,Dash 的方式 API 不是很全面,所以,Dash 不是很赞成。

1. lzfse 方式

/Applications/Xcode.app/Contents/SharedFrameworks/DNTDocumentationSupport.framework/Versions/A/Resources/external

在上面的路径下,我们可以看到一个 cache.db 文件,和一个 fs 的文件夹,

cache.db 是一个数据库文件,

cache.db 数据解析:

row_id: id
uuid: 现在的文档因为是在线查看,文档中还包含了很多图片,视频,文本等内容, uuid 是内置浏览器加载的uuid, 我们在抽取 document_apis 的时候,只需要解析文本文件即可。
data_id: 当前 uuid 对应在 fs 文件下的文件名。
offset: 因为 fs 是字节码文件,我们读文件的时候,这个字段可以标识读取字节码开始位置。
lenght: 当前 uuid 所占字节码文件中的长度。

fs 文件夹是包含浏览器加载的数据文件夹,都属于二进制文件,利用 uuid 过滤出文本文件后,可以利用 lzfse 算法解压缩,就可以读取到文件的内容。

文件解析:
我们拿到的文件不仅包含了 API 的一些说明,还包含类的说明,协议的说明,全局实例等等...从上图解析后的文件,可以拿到当前的 API 名,所属头文件和 frameworks 的名字。

metadat json 对象字段说明:
title: API name
roleHeading: 当前所属类型, instance method就是实例方法,function 是c语言的函数。
e xternalID:当前id, 包含类库名,头文件名,function 类型没有头文件名,所以这部分API 的提取需要全局查找,不允许重复定义。

以上就是 lzfse 的提取方式,参考链接就是 GitHub 上提供的工具包。

2. Dash 方式
这种提取方式是依据 Dash 软件提取的,这种提取方式提取的 API 比较方便,快捷,但是也有一定的缺陷:

  1. 没有头文件的定义
  2. API 不全,可能会有缺失 Dash 是 mac 下的文档管理软件,可以离线下载帮助文档。安装 Dash 后,直接下载 ios 的文档,文档路径在
~/Library/Application Support/Dash/DocSets

我们可以看到一个.docset 的文件,显示包内容,在 Resources 文件夹中可以看到两个 docSet.dsidx 和 optimizedindex.dsidx 两个数据库文件,不能直接使用数据库客户端工具打开,把两个文件重新命名为.db 文件,在使用客户端工具就可以打开了。两个数据库内容感觉差不多,我们说下 docSet.dsidx 这个文件内容:

打开后有两张表,一个是 searchindex ,另外一个是 cache

searchindex表说明:
id : 标识id
name:API 名,类名...
type:类型,当前所属方法还是类....
path: 文档路径

cache表说明:
id: 标识id
name:同上
request_key: 可以根据path路径提取request_key
request_key_alias: uuid,这里的uuid和上面的uuid是一个意思。

Dash 这种方式也是可以提取出 API 的,但是个人感觉不太准确,不能用作构建私有库的 API。

结果

从上面两张图片来看,我们提取文件数量和数据库中查询的数据是一致的。
最后,本章的内容就介绍完毕,再次感谢各位程序员,测试人员在探索的道路上不断的付出,也希望有机会和大家一起研究探讨。

参考
https://github.com/ydkhatri/pyliblzfse


↙↙↙阅读原文可查看相关链接,并与作者交流