《反编译SpeedPro.apk的结果报告 — 评估混淆程度》
操作时间:2016-2-19
使用工具:ShowJava/JaDX0.6.1
报告版本:Version1
1.反编译结果概述
图 1 SpeedPro反编译结果目录结构
如图1所示,主要关注四个地方:首先java文件夹是项目源码java文件,包括项目所引用的SDK源文件和项目本身的各种类文件源码,是项目的核心文件,开发人员对此文件夹里面的源文件进行了较强的混淆处理,如图2所示。res是资源文件夹,基本上本项目的图片素材等资源文件及布局文件都在这里面;然后是AndroidManifest.xml配置文件,里面是本项目所需要的权限管理和四大组件中Activity及Service等各注册信息,assets文件夹里面的speedtest-server.xml是server的资源配置文件。下面是图2。
图2 Java文件的混淆处理效果
随便打开其中某一个文件可以发现,源码的各文件类名都被a、b、c、d、e、f等简单字母所混淆替换。
2.目录展示及其混淆程度的分析
经过观察AndroidManifest.xml以及res资源文件的内容可以得知本项目采用的IDE是Eclipse+ADT,且项目app名称为:SpeedPro,基础包文件是com.huawei.speedpro,targetSdkVersion是API19。
通常情况下,Android Apk混淆分两步走:一是混淆代码,二是混淆资源文件。下面就此两点进行混淆效果的评估。
新建一个同名项目,把反编译的结果放在编辑器里面,方便查看
2-1 res文件
根据上面的截图反编译结果可以看到,在res目录下熟悉的layout、drawable、anim、menu等文件夹是清晰可见的,内容也可以查看,所以结论就是,本Apk想必只对Java源码进行了混淆,而并没有专门对Android资源进行混淆保护。我们在开发过程中可以通过ProGuard或者DexGuard来保护我们的代码,从而实现相对的代码安全,但我们往往忽略对资源文件的保护。
取其中某一个xml布局文件:
反编译出来的结果是这样的,内容一坨一坨的挤在一起,尽管如此,但是其内容是完整的而且布局也是清晰的,只不过是排版变得挤了一点。
放在编辑器里面格式化一下就好看多了,便可以进行清晰的分析。
而图片资源及其命名也是一览无余原封不动的,如下所示。
2-2 Java文件
如图所示,明显进行了混淆。
如下图所示,当点进某一个文件之后会发现,可以看到的主要是进行了符号混淆和数据混淆,类名方法名变成了简单的字母表示,也就是说,对Android 代码进行混淆后,混淆器将代码中的所有变量、函数、类的名称加密为简短的英文字母代号,在APP被破解后以此来增加破解者对代码的阅读难度。而像setContentView()方法等传入的一串数字参数,其实就是一个资源的id值而已,那么这里反编译也就只能将相应的id值进行还原,而无法变成像R.layout.activity_main这样直观的代码展示。
2-3 引入的API
Vitamio视频多媒体开发框架
使用了Dom4j解析XML
使用了数据交换格式json
对视频处理的mp4parser
还有谷歌的腾讯的SDK等等…
我们无法直接使用反编译出来的这些API或SDK的源码,但是我们知道了是什么就可以自己新建项目,通过下载它们封装好的原版jar等相关文件加入到项目中。而恢复源码的难度在于对Java代码混淆的识别。
2-4 其他文件
AndroidManifest.xml
3.对APK混淆的一些认识
到目前为止,对于APK的保护,混淆技术是最为基本的保护方法。JAVA混淆工具也非常多,包括商业的、免费的、开放源代码的,大多是对Class文件进行混淆处理,也有少量工具首先对源代码进行处理,然后再对Class进行处理,这样加大了混淆处理的力度。
目前主要的混淆技术按照混淆目标主要可分为分别为:符号混淆、数据混淆、控制混淆、控制流重组、预防性混淆。
一、符号混淆
Class文件中有许多与程序执行本身无关的信息,例如变量名称、方法名称,并带有一定的含义,例如某个方法名为getKeyLength(),那么这个方法很可能就是用来返回Key的长度。符号混淆就是打乱这些信息,将其变成无任何意义的表示,例如:对于所有的方法从method_001开始编号;将所有的变量从vairant_001开始编号。符号混淆可对APK反编译带来一定的困难,从而达到保护APP安全的作用。
对于私有函数、局部变量,可改变它们的符号,也不影响程序的运行。但是一些接口名称、公有函数、成员变量,若有其它外部模块需要引用这些符号,往往需要保留这些名称,否则外部模块找不到这些名称的方法和变量。
二、数据混淆
数据混淆是对程序使用的数据进行混淆,可分为改变数据存储及编码和改变数据访问。
改变数据存储和编码可以打乱程序使用的数据存储方式。例如将一个有10个成员的数组,拆开为10个变量,并且打乱这些变量的名字;将一个两维数组转化为一个一维数组等。另外,一些复杂的数据结构,我们将打乱它的数据结构,例如用多个类代替一个复杂的类等。
改变数据访问,例如访问数组的下标时,我们可以进行一定的计算。
在实践混淆处理中,这两种方法通常是综合使用的,在打乱数据存储的同时,也打乱数据访问的方式。经过对数据混淆,程序的语义变得复杂了,这样也增大了APK反编译的难度。
三、控制混淆
控制混淆就是对程序的控制流进行混淆,使得应用APK更加难以反编译,通常控制流的改变需要增加一些额外的计算和控制流,因此在性能上会给程序带来一定的负面影响。有时,还需要在程序的性能和混淆程度之间进行权衡。
四、控制流重组
重组控制流也是重要的混淆方法。例如,程序调用一个方法,混淆后,可将该方法代码嵌入到调用程序当中。反过来,程序中的一段代码也可以转变为一个函数调用。另外,对于一个循环的控制流,为可以拆分多个循环的控制流,或者将循环转化成一个递归过程。这种方法最为复杂,研究的人员也非常多。
五、预防性混淆
这种混淆通常是针对一些专用的反编译器而设计的,一般来说,这些技术利用反编译器的弱点或者Bug来设计混淆方案。例如,有些反编译器对于Return后面的指令不进行反编译,而有些混淆方案恰恰将代码放在Return语句后面。这种混淆的有效性对于不同反编译器的作用也不太相同的。