iOS代码混淆原理

2020-07-04  本文已影响0人  U8SDK

我们在U8SDK官方SDK的iOS版本中, 除了AppStore官方支付之外还集成了第三方支付(微信支付H5和支付宝支付H5版本)。

如果用于企业签,不需要做任何处理,直接使用即可。 但是如果需要上架AppStore,我们需要屏蔽第三方支付。 这个我们后台设置开关,直接后台切换支付方式即可。 上架审核的时候, 切换为Appstore支付;审核通过的时候,切换为第三方支付。因为第三方支付,是H5方式,不会被机审检测到。 同时,防止被抽查,后台也可以设置,将每次前多少次支付,设置为AppStore支付,之后用第三方支付,降低被抽查到的风险。

但是只是做到这个还不够, 如果需要用这套SDK上架多个游戏,或者多个马甲包。 防止一样的代码被4.3的风险或者被代码标记的风险,我们需要对SDK的代码进行混淆, 每次出一个马甲SDK。

关于iOS代码的混淆, 网上有很多文章,但大多都是多年之前的纯字符随机替换,增加垃圾代码等,这种方式按照目前的机审政策,已经很难过审了。

所以,我们这里就U8SDK官方SDK项目中使用的一键混淆工具,来谈一谈iOS中的代码混淆设计。

项目在开发之初, 如果开发者或者运营经验丰富, 提前将混淆这个事情重视起来, 那么后期项目的混淆就会很简单。 可以事先指定代码编写规则,尽量保证类方法变量等的唯一性。 比如制定良好统一的编码规范:所有的类以X开头,所有的方法函数以F开头,所有的属性以P开头, 所有的内部变量以S开头等等。 那么在后续写混淆工具的时候,也许几行代码就可以搞定了。

但是我相信多数项目可能和我们一样,都是事后诸葛亮,等到需要做这件事情的时候,才发现代码命名随心所欲带来的代价。 但是,如果仅仅为了方便混淆来重写框架几乎是不可能的,程序研发这边也不愿意呀。

所以,我们就只能费些心思来写混淆脚本了。 我们选择python来写混淆工具,用python来干这个事情,还是很合适的。

在U8SDK官方SDK中, 我们给混淆工具定的最终目标是:一键混淆,混淆之后零编译错误,无需手动干预;在此基础上,尽可能地通用,防止后续其他项目需要用到。

基于此,我们首先就要确定一下混淆工具的主要功能点:


xsdk_ios_mix_01.png

列出了主要功能, 我们根据当前的审核机制大体来设计一下工具的整体混淆机制:

1、词汇替换

混淆,也就是替换, 将老的名称替换为新的名称。 之前网上很多都是使用纯随机字符来替换,但是目前这个方式风险很大,很容易被苹果检测出来有隐藏功能的意图。

所以,我们采用双词库的形式来进行混淆。

我们准备两套词库; 一套是常用的单词词库(词汇量大概1000个),一套是程序常用单词词库(词汇量大概200个)。

在生成混淆后新名称的时候, 我们根据需要, 从两套词库中随机单词,进行拼接。

比如混淆类名称的时候, 当前有一个类名是AppStorePay。 我们先从常用词库中随机单词进行拼接,直到长度大于等于AppStorePay长度的时候为止。 然后再从程序词库中随机一个单词作为后缀,这样混淆后的名称可能是OneForTestListener这样的形式, 看起来就接近了正常的类名命名。

另外混淆的时候, 我们记录一个已经生成的新的名称的列表, 如果生成的新名称已经存在,那么重新生成。 防止生成的新名称重复导致问题。

2、混淆思路

混淆的时候, 我们可以逐行混淆, 但是这种方式, 误差可能会很大。 我们的目标是, 混淆之后一次性编译通过, 不需要再手动修改某些混淆失败的地方。 所以我们放弃了逐行混淆的方式,而是设计一种更加精细化的混淆方式。
另外混淆的方式,根据总体目标,我们希望尽可能地符合iOS语法通用的规则,而不简简单单地适应U8SDK官方SDK这个项目(防止后续我们其他项目也需要做混淆)。

3、混淆工具设计

为了能够尽可能地精细化混淆,我们设计并抽象出了一些符合iOS代码结构的对象:


xsdk_ios_mix_02.png

图中我们可以看到, 我们首先设计了四个类。:

XFolder:  代表一个代码目录
XClass:  代表一个类文件
XFunction: 类代表一个类中的一个函数
XProperty: 类代表一个类中的一个属性

代码实现提要:混淆工具运行之后,会调用XFolder中的load方法,加载XFolder对应目录下的所有class文件并解析出所有Class文件中的函数和属性。

将代码类文件加载并解析之后, 我们就可以开始执行混淆计划了。 我们设计了一系列混淆实现类,来进行混淆:


xsdk_ios_mix_03.png
1、PCHCodeMixer: 对XSDK.pch文件中定义的全局变量进行混淆,同时对源码中所有引用的地方进行替换

2、PropertyCodeMixer: 对每个类中定义的属性进行混淆, 同时对源码目录中所有引用的地方进行替换

3、FunctionCodeMixer: 对每个类中定义的函数进行混淆,同时对源码目录中所有引用的地方进行替换

4、FunctionCodePostMixer: 对函数内部定义的属性进行混淆,同时在合适的地方插入垃圾代码。

5、ClassCodeMixer:对类名称进行混淆,同时对源码目录以及xcode工程文件中所有引用的地方进行替换

6、ResourceMixer:对资源进行混淆, 对所有图片文件进行md5变更,对所有图片名称进行混淆,对所有源码目录以及xcode工程文件中所有引用的地方进行替换

7、GlobalNameMixer: 对目录,对框架名称,对Bundle名称等全局民名称进行混淆。 同时对所有文件和xcode工程文件中所有引用的地方进行替换

8、DemoMixer: 对demo工程中的引用进行替换。

9、DocMixer:对文档中对应的引用进行替换。

有了以上这些组件,就可以完成对框架代码和资源进行混淆和替换。最后两个是辅助的mixer类,主要完成对demo工程和文档内容的替换。

混淆的时候, 我们通过正则表达式来解析对应的函数和属性; 但是因为iOS的特殊性, 函数中有中括号,而且函数的地方可以无限嵌套,所以,在对函数和函数引用进行处理的时候,可以采用栈结构来解析和匹配。

另外解析函数体内容的时候, 我们也是采用栈结构来解析。 也就是先解析出了类中所有的函数名称, 然后从后往前解析函数体内容,这样解析也方便很多。 其他地方的混淆,基本用正则表达式就可以完成,只是写正则的时候或者用正则匹配替换的时候, 尽可能的精细化规则,严谨地匹配。替换的时候, 按照被替换串的长度,优先替换长串,再替换短串。

目前经过多个项目的实践,U8SDK官网SDK经过混淆工具混淆之后, 无需任何手动修改和替换。

如果您也对手游聚合SDK开发感兴趣,也欢迎关注U8SDK技术博客:www.uustory.com, 或者可以加入我们的聚合SDK技术交流QQ群:207609068

上一篇下一篇

猜你喜欢

热点阅读