如何进行SO加固?SO库加密保护有哪些方法?

SO库文件是Linux下动态链接库,相比DEX文件,SO文件安全性更高,反编译难度更大。大多数Android 的开发者喜欢把核心算法、重要协议等放在SO库文件中,因此SO加固是Android安全保护核心问题,本文将对如何进行SO加固保护做简单介绍。

SO加固大概可以分为有源保护和无源保护,有源保护分为自解密、混淆、源码VMP等,无源保护分为加壳、VMP保护。  

SO加固-有源保护:

自解密保护的原理是:先加密要加密的函数或者段,再加载SO文件,解密之前加密的函数和段。由于运行后要解密相关的逻辑,因而破解者只要在SO文件运行后,DUMP内存,就可以获取解密后的逻辑,破解难度低,因而自解密保护普遍存在安全强度低、维护成本高的缺点。

市面上常用SO源码保护是基于LLVM的混淆,通过指令替换、控制流扁平化和虚假控制流等角度去混淆源码。如下源码为测试源码,试试一个简单的校验函数,测试程序是ARMV7A架构下的编译。



 混淆前的控制流程图

对上面的源码进行一些混淆,在增加了虚假控制流、指令替换和控制流平坦化的处理后,控制流的复杂度增加。如下图所示,增加了控制流程图复杂度,加大了逆向分析的难度。基于LLVM的源码混淆比较灵活,可以根据不同的安全需求配置不同的安全策略,混淆程度越高,则性能影响越大,文件膨胀越多。在对游戏影响很小的前提下,混淆能做的比较有限,导致安全强度不够,混淆存在安全强度和性能不可兼得的问题,不好找到平衡点。


        由于源码混淆的方式在安全强度方面仍然不够,因而出现了源码VMP的方案。

相对基于LLVM的混淆,VMP安全强度更高,并且对SO文件的体积也较小,加固后的SO主要分为虚拟数据VMData和解释器handler,如下图所示为例子的VMData数据。
                                                                      解释器handler的控制流


采用VMP保护对原函数执行的性能有比较大的影响,对所有方法VMP是无法满足游戏方对性能的要求。VMP的在不了解VMData和handler的对应关系的情况下,安全强度非常高,若相关的对应关系被破解者掌握,则也可以被还原,不过handler的复杂性一般比较高,并且对应关系可以做到随机处理,因此安全强度是完全满足游戏方的要求。上面说的基于源码的保护都存在一个相同的问题是接入成本高,需要处理源码就需要有本地工具,特别有些游戏引擎非开源,那基于源码的保护则无法接入。

SO加固- 无源码保护 :

无源码保护的加壳,目前加壳的方法有比较多,安全强度差别也比较大,不过核心是自定义linker。在壳SO文件被执行后需要先解密、还原被保护的SO文件,然后使用自定义linker加载被保护的SO,最后将执行权还给被保护的SO。加固的静态保护强度很高,原SO文件完全抹去,但是动态执行后会还原部分内容,开发者还可以配合反调试、反Dump等技术使用,弥补SO加固在内存安全强度上的缺点。尽管加固存在着比较明显的缺点,但是加固也存在很大的优势-对APP性能影响最小,运行时不会增加任何开支,并且接入成本低,不需要有任何接入的成本。

无源码VMP与源码VMP原理上是相似的,加固处理后最关键的部分仍然是虚拟数据VMData和指令解释执行器handler。VMP处理时需要将原指令处理成VMData虚拟数据,并且插入解释器handler。

  

无源码VMP handler

VMP处理的安全强度高,逆向分析成本高,但是存在影响性能的问题。

SO加固保护总结:

SO加壳保护对性能影响最小,无源码方案接入成本最低,VMP保护安全强度最高。采用SO加固+无源码VMP结合的方式既可以满足对性能影响最小化的需求,同时又可以有效防止SO库文件被反编译,保障Android程序的安全。

相关阅读:

Android应用安全提升攻略

网易易盾最新一代Java2c加固解读

干货分享 | Unity手游安全加固解析及实践

如何系统有效地提升Android代码的安全性?