综合技术

基于多重替换方式的iOS代码混淆方案

微信扫一扫,分享到朋友圈

基于多重替换方式的iOS代码混淆方案
0

2019年04月17日 阅读 19

基于多重替换方式的iOS代码混淆方案

导语

本文将从几个方面阐述什么是代码混淆以及它的应用方法和会遇到的问题,同时分享了TalkingData自己研发的代码混淆方案,欢迎转发收藏。

一、 概述

1.1 什么是代码混淆?

代码混淆 ,是将计算机程序的代码转换成一种功能上的等价,但是难于阅读和理解的形式的行为。代码混淆可以用于程序源代码,也可以用于程序编译而成的中间代码。执行代码混淆的程序被称作 代码混淆器 。目前已经存在许多种功能各异的代码混淆器。

代码混淆的主要目的是为了保护源代码,阻止反向工程。反向工程会带来许多问题,诸如知识产权泄露、程序弱点暴露易受攻击等。

本方案主要针对程序源代码中的字符串、类名以及函数名称等进行混淆。由于此种混淆方式较为简单,避免了由于操作中间代码而容易改变程序逻辑等。

1.2 代码混淆的通用方法

  • 将代码中的各种元素,如变量、函数、类的名字改写成无意义的名字。 比如改写成单个字母,或是简短的无意义字母组合,甚至改写成__这样的符号,使得阅读的人无法根据名字猜测其用途。

  • 重写代码中的部分逻辑,将其变成功能上等价但是更难理解的形式。 比如将for循环改写成while循环、将循环改写成递归、精简中间变量等等。

  • 打乱代码的格式。 比如删除空格,将多行代码挤到一行中,或者将一行代码断成多行等等。

1.3 代码混淆的一些问题

  • 被混淆的代码 难于理解 ,因此调试除错也变得困难起来。开发人员通常需要保留原始的未混淆的代码用于调试。

  • 对于支持反射的语言,代码混淆有可能与 反射发生冲突

  • 代码混淆并不能真正阻止反向工程,只能 增大其难度 。因此,对于对安全性要求很高的场合,仅仅使用代码混淆并不能保证源代码的安全。

二、 实际问题

由于TalkingData合作的不乏金融类、证券类行业企业,此类行业的特点是和人民币息息相关,成为很多不法分子来牟取不法利益的重灾区,因此安全便是此类行业的相关应用程序的重中之重。以往采用寻常的方式对SDK进行编译打包,虽然说像AppStore这样的应用商城会采用一些代码级别的安全措施,但是这些安全措施也不乏被破解的可能,技术总是有缺陷的。

2.1 问题一:现有加密/加固服务的工具提供商是否满足我们的需求

在前期调研过程中,我们测试了两家SDK加密加固工具,虽然两者均能够完成对SDK的加固,也实现了代码逻辑的混淆,甚至在原有的代码中插入了混淆视听的“垃圾代码”等等,但是两者均是通过修改代码编译的中间代码完成的代码加固。此类加固方式均是通过修改原始编译器的方式进行的操作,或者直接提供了一套修改后的编译器替换官方编译器,此类方式不得不说绝对是大牛作品,但是针对我们自由的SDK服务来说,此类方式可能并不适合,原因如下:

  • 通过修改系统编译器的方式属于黑盒方式,我们并不知晓其中是否有某些不该有的操作;

  • 编译器的替换等操作会影响或者污染系统纯净环境,使得打包后的SDK无法通用;

  • 此类方式编译打包SDK后,SDK的大小会受到很大的影响,因为为了对代码逻辑进行混淆,增加了很多“垃圾代码”,以混淆视听;

  • 此类方式对SDK的加密/加固可能会导致AppStore审核受影响,过度混淆在AppStore是不允许的(原因是AppStore无法预知你的意图以及是否该应用是一个壳子应用)。

2.2 问题二:开源的一些混淆工具是否满足我们的需求

在网络上也有很多相关的代码混淆工具,有的甚至能够在代码混淆的基础上,加入逻辑混淆等操作,但是这些工具基本上已经停止更新,代码的状态还停留在早期Objective-C的版本上,如果我们对其进行改造,所花费的时间精力有点得不偿失。另外一点,开源工具是存在一定的开源协议限制的,因此所有我们来说,使用后也必须遵循相应的协议,但是面对我们当前的业务形式,暂时还不太适合。

2.3 问题三:自研混淆工具所面临的问题

面对各种混淆工具,最终决定自研一套符合我们当前要求,并且能够完美集成到当前打包流程中实现自动化的混淆工具,该工具和现有打包能够完整集成,对现有SDK代码以及打包脚本代码无侵入性。但是这里也会遇到一些问题:

  • 打包脚本是使用shell进行代码的前期准备和最终的归档操作的,因此我们的混淆工具是否能够很好的使用shell调取;

  • 混淆工具的安装、更新是否平滑,对各项现有服务无停机、延迟等影响;

  • 混淆工具是否能够独立git管理,在打包脚本中进行版本检查与更新等;

  • 面对不同的业务线,混淆工具是否能够适配各个业务线;

  • 针对SDK的特性,部分内容是无需混淆的(例如供开发者使用的对外接口文件等),混淆工具是否能够有选择性的混淆等;

  • 混淆工具是否有缓存功能,针对业务完全相同的代码,能够直接从历史混淆成果中提取,为无需重复执行等;

  • 面对如上各个问题,最终我们完成了符合我们当前需求的混淆工具。

三、 混淆工具CodeObscure

该工具主要用于Objective-C代码混淆,以避免class-dump等反编译代码工具解读代码,提高SDK的安全性。该工具最终设计为基础配置后全自动运行,无需对现有打包脚本以及项目工程进行其他额外操作。

3.1 基础原理

此工具使用Ruby语言编写。此工具会默认遍历项目属性、方法和类名进行混淆。当然如果简单的进行遍历的话,会产生无穷无尽的错误,因为你不能混淆Apple提供的官方API,也不能混淆framework和.a的静态编译的库。所以在混淆代码的时候必须排除掉。该工具已经内置了过滤系统的方法。如果项目中使用Pod或者使用了静态库,或者其他比较特别的第三方库,可以使用codeobscure -l [路径1,路径2..]的方式去过滤这些库文件,运行codeobscure -o [项目名.xcodepro]开始混淆你的代码。

当然并不意味这你运行了就一定没错误,该工具最大的简化了混淆代码的工作,由于不同的人编写的代码可能各不相同。假设你调用了NSClassFromString("classNameA")而这个类正好被混淆了,它不识别classNameA到底是什么。那么怎么解决这个错误呢。最简单的方式就是在codeObfuscation.h中查询classNameA并删除它的#define即可。

!如果你运行了codeobscure -l [路径1,路径2..],那么它会记录下来要过滤的东西。如果你下次不想过滤已经过滤的库,运行codeobscure -r来重置。

3.2 混淆方式

一般情况下,放置class-dump较为有效的方法是对代码进行字符串替换,因此该工具着重实现了字符串替换的方法,针对扫描项目工程得到的属性、方法和类名等进行字符串替换,最终通过#define的方式在codeObfuscation.h中定义。字符串的替换提供了两种字符串生成方式, 随机字符串随机单词

随机字符串 ,即通过随机函数生成一定长度的字符串,对属性、方法和类名等进行等价替换;

随机单词 ,即通过随机单词生成工具得到随机单词列表,之后通过随机函数选择某些单词,对属性、方法和类名等进行等价替换。(这里随机单词生成工具使用了RandomWord类库)

注:滑动查看完整代码(下同)

// 生成结果示例:
  r :#define getHeight ZbgTCtOTDmEazebk
  w :#define getHeight nodulatedBasutoland复制代码

3.3 混淆字符缓存

在项目迭代开发发布过程中,大多数情况下并不会改变代码以及代码逻辑,仅仅是重新打包或者微小的改动等,此类情况下再次对项目工程进行混淆的时候,就不需要重新设置过滤的字符以及文件。针对此种情况,该工具提供了过滤字符缓存的工具,使用微型数据库SQLite3对混淆中的一些字符进行缓存,待下次使用的时候直接加载而无需去遍历项目代码。

!由于Apple新版系统有SIP(系统完整性保护)默认是开启的,所以由于安装方式不同,可能在运行命令的时候出现:attempt to write a readonly database (SQLite3::ReadOnlyException)的问题。如果出现这个问题,请在命令行上加上sudo。

3.4 该工具目前的不足

  • 由于该工具是针对我们的SaaS产品进行的研发,因此并不适用于所有的业务线,例如一些定制版、POC相关以及其他非SaaS平台,如果该混淆工具的最终混淆结果能够顺利的通过AppStore的严格审查,我们将继续扩展该工具,包括业务线支持、混淆的级别等。

  • 该工具是使用Ruby语言编写的,以及使用了SQLite3、RandomWord类库,因此在使用前,需要配置相关的设备,提前安装好所需的类库;

  • 该工具在后续使用过程中可能还会遇到不可预知的问题,因此在使用时需要谨慎对待。

3.5 安装指南

由于本项目资源属于内部使用,此部分暂不分享。

3.6 使用实例

使用过程中请使用 绝对路径

  • 实例1:混淆方法、类名、属性,过滤Pods和Download

codeobscure -o /Examples/Messenger.xcodeproj  -l /Examples/Pods /Examples/Download复制代码
  • 实例2:仅仅混淆方法和类名

codeobscure -o /Examples/Messenger.xcodeproj -f f,c复制代码
  • 实例3:生成ignoresymbols文件,用于写入要过滤的关键字

codeobscure -i XcodeprojPath复制代码
  • 实例4: 重置-l记录的要过滤的关键字

codeobscure -r复制代码
  • 实例5:严格模式过滤,并且用单词模式进行替换。(如果代码中含有很多的KVO以及Runtime代码,使用严格模式,会更好的帮助你。)

codeobscure -o /Examples/Messenger.xcodeproj -t w -s复制代码

3.7 codeobscure -h 命令帮助

使用工具是时候,路径直接用绝对路径,不支持相对路径。(直接把文件拖到终端显示出来的路径就是绝对路径)

Usage: obscure code for Objective-C project
-p, --prefix class name prefix   当前要混淆的项目类前缀(TDAT, TDAA, TDGA)
-o, --obscure xcodeproj path     要混淆的项目工程xcodeproj文件绝对路径
-l, --load path1,path2,path3     指定不需要混淆的文件绝对路径
-r, --reset                      重置 -l 记录的要过滤的关键字
-f, --fetch type1,type2,type3    获取需要混淆的类型, 默认参数是c,p,f。c:类名,p:属性,f:方法
-i, --ignore xcodeproj path      生成ignoresymbols文件,用于手动写入要过滤的关键字。eg:name,age ...
-t, --type replaceType           指定替换的形式,默认r。 r:随机字符串 w:单词
-s, --strict                     严格模式过滤,并且用单词模式进行替换。适用于KVO和Runtime比较多的代码
复制代码

四、 未来愿景

当前该工具已经在测试平台通过各项打包测试,在不久的将来,我们将在线上产品的打包中看到该选项,希望该工具能够达到预期的目标。在不断的产品演进过程中,该工具肯定会有所过时甚至不符合实际需求,因此该工具也会随着业务的优化改进而优化改进,尽最大努力使得该工具能够发挥其微小“螺丝钉”式的效能。

作者:TalkingData 张永超

部分内容来源于百度百科

阅读原文...

微信扫一扫,分享到朋友圈

基于多重替换方式的iOS代码混淆方案
0
稀土掘金

如何在收到 PFX 或 CER 憑證檔之後使用 OpenSSL 進行常見的格式轉換

上一篇

Android Handler 源码探索

下一篇

评论已经被关闭。

插入图片

热门分类

往期推荐

基于多重替换方式的iOS代码混淆方案

长按储存图像,分享给朋友