专栏首页老欧说安卓Android开发笔记(七十三)代码混淆与反破解

Android开发笔记(七十三)代码混淆与反破解

代码混淆

ProGuard是ADT自带的apk混淆器,它的用途有: 1、压缩apk包的大小,能删除无用的代码,并简化部分类名和方法名。 2、加大破解源码的难度,因为部分类名和方法名被重命名,使得程序逻辑变得难以理解。 代码混淆的规则在proguard-project.txt中编写,然后在project.properties补充规则文件的路径,如下所示:

proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

下面是proguard-project.txt的一个例子:

#指定代码的压缩级别
-optimizationpasses 5
#是否使用大小写混合
-dontusemixedcaseclassnames
#优化/不优化输入的类文件
-dontoptimize
#是否混淆第三方jar包
-dontskipnonpubliclibraryclasses
#混淆时是否做预校验
-dontpreverify
#混淆时是否记录日志
-verbose
#混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解
-keepattributes *Annotation*

#保持JNI用到的native方法不被混淆
-keepclasseswithmembers class * {
    native <methods>;
}

#保持自定义控件的构造函数不被混淆,因为自定义控件很可能直接写在布局文件中
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

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

#保持布局中onClick属性指定的方法不被混淆
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

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

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

#指定哪些第三方jar包需要混淆
#-libraryjars libs/bcprov-jdk16-1.46.jar

#保持哪些系统组件类不被混淆
-keep public class * extends android.app.Fragment  
-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 * extends android.support.v4.**
-keep public class com.android.vending.licensing.ILicensingService

#保持哪些第三方jar包不被混淆
-keep class org.bouncycastle.**
-dontwarn org.bouncycastle.**

下面是进行代码混淆时的注意事项: 1、jni的方法要屏蔽混淆,因为so库要求包名、类名、函数名要完全一致 2、可能会在布局文件中直接引用的类名或方法名,要屏蔽混淆。包括自定义控件、布局中onClick属性指定的方法等等。 3、保持第三方jar包不被混淆,有时需要把“keep class”提到“dontwarn”前面。 4、jar包的文件名中不要有特殊字符,比如说“(”、“)”等字符在混淆时就会报错,文件名最好只包含字母、横线、小数点。 5、使用WebView时,会被js调用的类和方法,要屏蔽混淆。具体做法除了要在proguard-project.txt加上如下说明外,还要在java代码中调用一下js使用的方法,才能保证内部类与方法都不会被混淆。有关WebView中调用js的说明参见《Android开发笔记(六十四)网页加载与JS调用

-keep class com.example.exmweb.WebActivity$MobileSignal{
    public <fields>;
    public <methods>;
}

防二次打包

前面的《Android开发笔记(七十)反编译初步》提到,apk破解得到smali文件后,可以进行修改并重新打包,从而制造一个山寨的APP。因此为了防止自己辛辛苦苦做的APP被别人山寨,就得在代码中加上防二次打包的处理。具体说来,首先开发者在打包前记下签名证书的MD码,然后在代码中获取app安装后的签名,对比两个签名的MD值是否一致,如果不一致就退出app,这样就能防止被二次打包了。 下面是获取apk签名的代码例子

	public static String getSignMD5(Context context) {
		String signMD5 = "";
		String packageName = context.getPackageName();
		PackageManager pkgMgr = context.getPackageManager();
		PackageInfo info = null;
		try {
			info = pkgMgr.getPackageInfo(packageName,
					PackageManager.GET_SIGNATURES);
		} catch (PackageManager.NameNotFoundException e) {
			return signMD5;
		}
		if (info == null) {
			return signMD5;
		} else {
			Signature[] signs = info.signatures;
			if ((signs == null) || (signs.length == 0)) {
				return signMD5;
			} else {
				Signature sign = signs[0];
				signMD5 = MD5Util.encrypBytes(sign.toByteArray());
				return signMD5;
			}
		}
	}

以上代码用到了MD5加密,加密算法参见《Android开发笔记(七十二)数据加密算法》。 下面是打包apk时的md5签名值的截图

下面是app运行时获取到的md5签名截图

花指令

代码混淆通过对类名和方法名重命名,只是加大了破解的难度,但并不能完全阻止代码被破解。有个办法就是通过让反编译程序出错,使得代码破解失败,花指令便是这样一种思想。花指令(junk code)意思是程序中加入一些与业务无关的指令,希望在反汇编的时候出错,让破解者无法正确地进行反汇编工作,从而迷失方向。常见的花指令常常是随意跳转,一旦目标位置是另一条指令的中间,反汇编的时候便会出现混乱。下面是花指令的一段示例代码(在jd-gui 0.3.6和1.4.0版本上都测试过,加了花指令的函数就无法正常破解):

		//花指令开始
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader("/proc/net/arp"));
			String line;
			while ((line = br.readLine()) != null) {
				String[] splitted = line.split(" +");
				if (splitted.length >= 0) {
					break;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//花指令结束

当然,除了上面说的代码混淆、防止二次打包、花指令等等技巧,还有其他的一些技术手段,下面是其他几种代码加密方式: 1、把部分代码写入jni接口,因为so库难以反编译。例如在做签名校验时,原签名的值就可以保存在jni接口中。jni的介绍参见《Android开发笔记(六十九)JNI实战》 2、把核心业务放到后端服务器上运行,app与服务器之前通过http接口通信。 3、使用第三方加密平台给app做加壳处理。 点击下载本文用到的代码反破解的工程代码 点此查看Android开发笔记的完整目录

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android开发笔记(四十四)动态UI事件

    动画事件主要用于Animation控件,可监控动画开始、结束、重播等行为。相关类名与方法说明如下: 监听器类名 : AnimationListener ...

    用户4464237
  • Android开发笔记(二十三)文件对话框FileDialog

    对话框是人机交互的有力工具,Android自带了几个常用的对话框,包括AlertDialog提示对话框、ProgressDialog进度对话框、DatePi...

    用户4464237
  • Android开发笔记(八)神奇的shape

    shape意即形状,是Android中描述规则几何图形的定义,ShapeDrawable其实就是Drawable的一个子类。...

    用户4464237
  • Android 混淆打包

    Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。

    Yif
  • 详解Android的反编译和代码混淆

    1、apktool(资源文件获取) 作用:资源文件获取,可以提取图片文件和布局文件进行使用查看

    砸漏
  • android代码混淆

    proguard 原理 Java代码编译成二进制class 文件,这个class 文件也可以反编译成源代码 ,除了注释外,原来的code 基本都可以看到。为了...

    xiangzhihong
  • Android项目实战(二十五):Android studio 混淆+打包+验证是否成功

    听着music睡
  • Android如何防止apk程序被反编译

    作为Android应用开发者,不得不面对一个尴尬的局面,就是自己辛辛苦苦开发的应用可以被别人很轻易的就反编译出来。

    阳光岛主
  • Android Studio实现打渠道包,切换环境,混淆配置等

    最近遇到项目从Eclispe迁移到Android studio,以前的Ant自动打包脚本已经兼容不好了,所以用了Gradle实现打渠道包,切换环境等。

    开发者技术前线
  • 关于AndroidStudio混淆打包 proguard-rules.pro 的配置关于AndroidStudio混淆打包 proguard-rules.pro 的配置

    Xiaolei123

扫码关注云+社区

领取腾讯云代金券