Android代码混淆技术

代码混淆技术的目的简而言之,由于Java程序比较容易被反编译,为了防止别人反编译源代码,窃取应用程序中的核心技术,或者说是为了增加反编译的难度,可以通过代码混淆技术增加对源代码的保护。

一、ProGuard简介

        ProGuard是一个免费的java类文件压缩、优化、混淆器。

        它探测并删除没有使用的类、字段、方法和属性。它删除没有用的说明并使用字节码得到最大优化。它使用无意义的名字来重命名类、字段和方法。优化的步骤分析和优化了类方法的字节码;混淆的步骤使用无意义的名字来重命名类、字段和方法。这些最初的步骤,使代码库更小,更高效,更难以进行逆向工程。最后的预验证步骤,为这些类增加了预验证信息,这是为了在 Java 6版本中优化启动时间。

        所有这些步骤都是可选的。例如,ProGuard同样可以被用于仅仅列出应用程序中的没有被调用的代码,可以提前检测和返回java6中存在的类文件。


图16-5  ProGuard处理流程图


        ProGuard读取输入的jar文件(或war文件、ear文件、zip文件或目录)。然后进行压缩、优化、混淆和预校验步骤。或者,可以进行多个优化过程,一个步骤通常紧接着另一个压缩步骤。ProGuard的处理结果将会写入到jar文件(或war文件、ear文件、zip文件或目录)中。输入可能包含资源文件,其名称和内容,可以有选择地更新,以反映混淆后的类名。

        ProGuard的要求到指定的库JAR文件(或war文件、ear文件、zip文件或目录)。这些都是在编译过程中所需要的库文件。ProGuard使用它们来妥善处理重建类所必需的依赖关系。库JAR文件本身将始终保持不变。

        ProGuard的使用目的:

        1)为了更快的网络传输,快速装载和更小的内存占用,创建更加紧凑的安装文件;
        2)为了保护软件的知识产权,创建更为坚挺的程序和程序库,使得逆向工程更加困难;
        3)删除源文件中的没有调用的代码;
        4)充分利用java6的快速加载的优点来提前检测和返回java6中存在的类文件。

        例如,下面的配置选项包含所有的applet在一个jar文件中:
-keep public class * extends java.applet.Applet

        ProGuard的是快速的。它只需几秒钟就可以处理几兆的程序和程序库。ProGuard的是一个可选的图形用户界面的命令行工具。它还为Ant和JME配备了无线工具包插件。

二、ProGuard使用

        在Android 2.3以前,Android混淆代码只能通过手动安装运行proguard来实现代码混淆,其实现过程比较繁琐,Proguard的使用说明及安装文件可以访问http://proguard.sourceforge.net/。而在Android 2.3以后,Google已经将Proguard工具加入到Android SDK的工具集里,具体路径为:SDK\tools\proguard。

        下面以一个例子,说明如何使用ProGuard。

        这里,我们用到的工程是在讲解第六章(Drawable分类汇总)时编写的Demo。在工程目录的根路径下,会有一个proguard的配置文件proguard.cfg。也就是说,我们可以通过简单的配置,就能在elipse工程中直接使用ProGuard混淆Android工程。


图16-6  工程根目录



        可以看到proguard.cfg已经帮我们写好了优化代码脚本,内容如下:

01 -optimizationpasses 5
02 -dontusemixedcaseclassnames
03 -dontskipnonpubliclibraryclasses
04 -dontpreverify
05 -verbose
06 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
07  
08 -keep public class extends android.app.Activity
09 -keep public class extends android.app.Application
10 -keep public class extends android.app.Service
11 -keep public class extends android.content.BroadcastReceiver
12 -keep public class extends android.content.ContentProvider
13 -keep public class extends android.app.backup.BackupAgentHelper
14 -keep public class extends android.preference.Preference
15 -keep public class com.android.vending.licensing.ILicensingService
16  
17 -keepclasseswithmembernames class * {
18     native <methods>;
19 }
20  
21 -keepclasseswithmembers class * {
22     public <init>(android.content.Context, android.util.AttributeSet);
23 }
24  
25 -keepclasseswithmembers class * {
26     public <init>(android.content.Context, android.util.AttributeSet, int);
27 }
28  
29 -keepclassmembers class extends android.app.Activity {
30    public void *(android.view.View);
31 }
32  
33 -keepclassmembers enum * {
34     public static **[] values();
35     public static ** valueOf(java.lang.String);
36 }
37  
38 -keep class implements android.os.Parcelable {
39   public static final android.os.Parcelable$Creator *;
40 }

        从脚本中可以看到,混淆中保留了继承自Activity、Service、Application、BroadcastReceiver、ContentProvider等基本组件以及com.android.vending.licensing.IlicensingService。

        并保留了所有的Native变量名及类名,所有类中部分以设定了固定参数格式的构造函数,枚举等等。(详细信息请参考<proguard_path>/examples中的例子及注释。)

        打开default.properties文件后可以看到,如图所示:


图16-7  修改前的default.properties文件



        开发人员只需打开default.properties文件,并且按照Google开发文档所描述的,在文件中加入proguard.config=proguard.cfg一行,即可完成对ProGuard的配置。


图16-8  修改后的default.properties文件



        加入配置后,重新编译导入正常签名的APK文件即可。具体方法不做详细分析。

        想要验证混淆结果,我们必须采用反编译工具测试ProGuard是否有效。

        首先,我们从谷歌的代码库中 http://code.google.com/p/dex2jar/ 下载dex2jar工具,用于还原.jar文件。下载完成后,进行解压操作,解压完成后我们会发现在目录中包含dex2jar.bat和classes.dex文件。

        将生成的APK文件用解压文件解压,得到Classes.dex文件并将其放入到dex2jar解压目录中,并调用dex2jar.bat classes.dex命令行来还原jar文件。

        看到命令行成功结束之后,dex2jar 文件夹里就会有“classes.dex.dex2jar.jar” 文件了,这个就是 传说中的 jar包了。


图16-9  dex2jar工具命令行示意图



        最后,我们来验证混淆结果。要验证混淆结果,必须查看.jar文件;这一步就是传统的反编译了,需要辅助工具。这里用到的工具是jd-gui,您可以从http://java.decompiler.free.fr/?q=jdgui下载获得,也可以通过其他方式下载。

        用jd-gui打开“classes.dex.dex2jar.jar”,我们可以看到工程的目录结构如下:


图16-10  混淆后的工程目录结构


        可以看出经过混淆后的代码其类名、字段名、变量名等都变成了没有意义的字符。如果没有进行混淆,反编译的结果中所有的类名、字段名、函数名等将和编译前没有太大差别,对于逆向工程而言非常容易。


Demo源代码下载:    Drawable_Test.rar (894.6 KB, 下载次数: 5) 

你可能感兴趣的:(java,优化,android,jar,工具,反编译工具)