Android代码混淆防止反编译APK获取源码

上一篇说了如何反编译APK文件获取Android源代码,但是如果所有的APK文件都可以随随便便被反编译,岂不是安全性也忒低了~所以这次说一下如何通过代码混淆的方式,提升APK文件的安全性,保护Android源码不那么容易被获取。

Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码。为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆。

混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。被混淆过的程序代码,仍然遵照原来的档案格式和指令集,执行结果也与混淆前一样,只是混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,在缺乏相应的函数名和程序注释的况下,即使被反编译,也将难以阅读。同时混淆是不可逆的,在混淆的过程中一些不影响正常运行的信息将永久丢失,这些信息的丢失使程序变得更加难以理解。

混淆器的作用不仅仅是保护代码,它也有精简编译后程序大小的作用。由于以上介绍的缩短变量和函数名以及丢失部分信息的原因, 编译后 jar 文件体积大约能减少25% ,这对当前费用较贵的无线网络传输是有一定意义的。

下面用一个demo来演示代码混淆的步骤:

首先我们新建一个Android工程,项目结构如下图所示:

Android代码混淆防止反编译APK获取源码_第1张图片

我们可以看到,在项目结构图中存在两个文件:proguard-project.txt和project.properties,这两个文件就是我们代码混淆需要用到的文件,我们打开project-.properties文件,在里面添加一行代码:proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt,如下图所示:

Android代码混淆防止反编译APK获取源码_第2张图片

下面为了测试代码混淆的效果,我们在MainActivity中添加几个方法,主要代码如下所示:

package cn.yubo.test;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    public void btnclick(View view){
    	Toast.makeText(this, "hello, world", Toast.LENGTH_SHORT).show();
    	fun3();
    }
    
    private void fun1(){
    	Log.d("yubo", "hello");
    }
    
    private void fun2(){
    	fun1();
    }
    
    private void fun3(){
    	fun2();
    }

}
这里就是随便写了几个方法,然后在按钮的点击事件方法中调用,下面我们就可以导出apk包了,导出apk包的方法,是在项目上右键---->export,如下图

Android代码混淆防止反编译APK获取源码_第3张图片
一直next下去,到需要使用keystore的一步时,如果没有keystore,我们可以自己创建一个keystore,如果有,可以直接使用,创建keystore的方法,就是指定keystore的路径和密码,这里比较简单,然后再next下去,到最后一步指定apk的导出路径,finish之后就成功导出apk文件了

到这里,我们导出的apk文件就成功做了代码混淆的处理了,为了验证代码混淆的效果,我们使用之前反编译的方法,看看反编译获取的代码是什么样子,这里我放上一张截图如下:

Android代码混淆防止反编译APK获取源码_第4张图片

从上面的图中我们可以看到,之前写在MainActivity中的方法,经过反编译后,全部被替换成了方法名为a,b,c的方法,很明显代码混淆的效果出来了,当然,这里测试的只是代码混淆的一部分,代码混淆可以混淆很多类和方法,这里就不再赘述了,基本方法就是上面所说的~

下面给出从其他博客中拷贝过来的代码混淆参数,博客出处为:http://www.cnblogs.com/sunzn/archive/2013/03/06/2946952.html

-optimizationpasses 5                                                           # 指定代码的压缩级别
-dontusemixedcaseclassnames                                                     # 是否使用大小写混合
-dontskipnonpubliclibraryclasses                                                # 是否混淆第三方jar
-dontpreverify                                                                  # 混淆时是否做预校验
-verbose                                                                        # 混淆时是否记录日志
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*        # 混淆时所采用的算法

-keep public class * extends android.app.Activity                               # 保持哪些类不被混淆
-keep public class * extends android.app.Application                            # 保持哪些类不被混淆
-keep public class * extends android.app.Service                                # 保持哪些类不被混淆
-keep public class * extends android.content.BroadcastReceiver                  # 保持哪些类不被混淆
-keep public class * extends android.content.ContentProvider                    # 保持哪些类不被混淆
-keep public class * extends android.app.backup.BackupAgentHelper               # 保持哪些类不被混淆
-keep public class * extends android.preference.Preference                      # 保持哪些类不被混淆
-keep public class com.android.vending.licensing.ILicensingService              # 保持哪些类不被混淆

-keepclasseswithmembernames class * {                                           # 保持 native 方法不被混淆
    native <methods>;
}

-keepclasseswithmembers class * {                                               # 保持自定义控件类不被混淆
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);     # 保持自定义控件类不被混淆
}

-keepclassmembers class * extends android.app.Activity {                        # 保持自定义控件类不被混淆
   public void *(android.view.View);
}

-keepclassmembers enum * {                                                      # 保持枚举 enum 类不被混淆
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep class * implements android.os.Parcelable {                                # 保持 Parcelable 不被混淆
  public static final android.os.Parcelable$Creator *;
}

-keep class MyClass;                                                            # 保持自己定义的类不被混淆


你可能感兴趣的:(android,源代码,安全,反编译,代码混淆)