Page 308 - 《软件学报》2024年第6期
P. 308
2884 软件学报 2024 年第 35 卷第 6 期
类使得不同应用中引入的相同 TPL 会聚集到同一个簇, 从而摆脱对人工标注的 APP 与 TPL 对的依赖. 代表性的
方法有: AnDarwin [25] 、WuKong [11] 、LibRadar 和 [9] LibD [10] . AnDarwin 和 WuKong 是最早的基于该思路的方法, 它
们以应用中包含的所有子包为单位进行聚类, 将函数调用的 API 作为每个子包的特征向量, 对子包进行聚类识别
TPL. 这一方法依赖于假设 TPL 被众多 APP 使用且未经改变. 然而, 大部分情况下引入的 TPL 会通过混淆技术进
行优化, 使得方法的检测精度不高. 此外, 该方法不能识别 APP 中具体使用的 TPL 版本. 针对上述不足, LibRadar
和 LibD 提出了多层级聚类的概念, 考虑了子包路径之间的包含关系来提升聚类准确性. 基于聚类的检测方法与之
前的方法相比, 只要选取了合适的与 TPL 相关的特征, 则同样具备抗混淆, 准确率高的优点. 此外, 该检测方法能
发现新出现的 TPL, 能用于识别各种类型的 TPL, 而无需第三方库类型的先验知识. 当然, 该方法也同样存在一些
不足之处. 首先, 基于聚类的检测方法需要收集大量的 Android 应用; 其次, 对于使用频率低的 TPL 识别能力依然
有限, 越流行的 TPL 越容易识别; 最后, 在使用复杂混淆操作如代码优化和包结构平坦化的应用中人工设计的特
征不够稳定, 导致检测方法的抗混淆能力下降, 不能准确识别 TPL.
目前, 最新的方法是基于相似性比较的检测方法, 其基本思路是采用比较方式, 先为 APP 和 TPL 中的包、类
[14]
生成签名作为比较对象, 而后度量签名相似性, 当相似性超过阈值时识别出引入的 TPL. 代表性的方法有 LibScout 、
引入了类签名字典的概念用于表示一个
LibPecker [15] 、LibID [16] 和 Orlis [28] . APK 开发和发布过程中引入的混淆操作导致的标志符名称改变、包结构改变、
控制流改变等是造成基于相似性比较的 TPL 检测方法误检和漏检的主要原因. 因此, 现有的方法都致力于探寻合
适的表示方法刻画 TPL, 设计混淆后仍然保持不变的特征, 以提升检测精度.
LibScout 首次提出了 Merkle 树表示方法刻画待比较的 APP 和 TPL, 最顶层存储 TPL 或 APP 签名、第 2 层
存储包签名、第 3 层为类签名、最底层为方法签名, 签名的生成方式采用自底向上方式实现, 即先产生方法签名,
而后有类中的所有方法签名产生类签名, 依此类推. 在匹配阶段, 则采用自顶向下的方式进行匹配, 若 TPL 的
Merkle 树和 APP 中特定包的 Merkle 树之间的相似度超过阈值, 则认为该 APP 中引入了该 TPL. LibScout 采用的
签名机制确保在引入的 TPL 结构不变的情形下能有效应对标识符混淆操作, 然而在使用优化操作、压缩操作或
类重组混淆技术情形下则对抗能力不足, 尤其是在较多无用的类被删除的情况下, 会产生较高的漏检率. 此外, LibScout
在生成类签名时, 仅考虑了类的方法签名容易产生误报. 针对 LibScout 的签名机制存在的问题, LibPecker 在沿用
Merkle 树表示方法的基础上, 对签名机制进行了改进, 不仅考虑类自身信息, 如类内的函数信息和类的重要性, 还
考虑类与类之间的依赖关系, 设计了基于加权方式的签名机制. 与 LibScout 相比, 虽然 LibPecker 提高了 TPL 检测
的召回率和准确率, 但是仍然仅能有效应对标志符混淆而无法有效对抗优化操作、压缩操作或类重组等混淆.
不同于 Merkle 树表示方法, LibDetect [31] 和 Orlis 设计基于方法级字节码特征的表示方法, 该类方法的基本思
路是采用不同混淆操作后主要的代码改变体现在方法层面, 因此从方法层面捕获混淆后不变特征是应对混淆的有
效方法. 例如, LibDetect 设计了一组由 5 种不同的方法抽象表示构成的特征用于刻画 TPL 或 APP 的方法, 包括字
节代码、无地址表示、匿名表示、结构保持表示以及模糊结构保持表示, 且随着抽象程度加深, 更抽象的表示能
应对更多种混淆操作, 同时也可能导致更高的误匹配. 在 TPL 检测过程中, 给定 APK 中的方法 m, 借助于方法级
的 5 种不同抽象表示从 TPL 库中查找一个包含与方法 m 最为相似的方法的 TPL 作为候选, 依据方法-类隶属关系
将方法相似累积到类相似, 依据类-包隶属关系将类相似累积到包相似, 从而确定最终的 TPL. 然而, 在类重组混淆
情形下, 因为类隶属包会的随机分配使得从类级别相似累积计算包相似失效, 从而导致 TPL 检测不准确, 同样无
法有效应对类重组混淆.
LibID APK 或 TPL, 其基本思想是为在签名生成阶段, 为 APK 或
TPL 中的每个类生成一组类签名, 由所有类的类签名共同刻画一个 APK 或 TPL, 进而在检测阶段, 以类作为比较
对象, 兼顾类相似和类依赖关系相似性确定最终的 TPL. 每个类包含多个基本块, 通过构造控制流图可以从图上抽
取所有的基本块, 将基本块连同 4 个类特征, 包括类访问标识、父类名、类接口和方法描述一起生成类签名, 能抵
御标志符混淆、代码压缩、控制流改变和包扁平化. 在真实数据集上的实验验证结果表明在 ProGuard 缺省混淆
配置下, LibID 的检测精度约为 92%, 而采用扁平化混淆情形下, 检测精度下降到约 55%, 仍然不能有效应对扁平
化混淆.