Android混淆那些事儿

博客: 安卓之家
微博: 追风917
CSDN: 蒋朋的家
简书: 追风917

每日一景

Android混淆


Android混淆是Android开发者经常使用的一种用于代码防止被反编译的常见手法,一般在Release模式生效,主要有三个作用:
1 压缩、优化、删除代码;
2 一定程度上提高反编译后被读懂的难度;
3 通过删除代码功能实现的特殊作用。
比如在可以运用混淆技术在发布版本不打印 Log.d等调试信息,防止敏感信息泄露,而在dubug模式下可以打印所有调试信息方便调试。

Android混淆技术


1 Java类名、方法名混淆

Dalvik字节码包含了大量的调试信息,如类名、方法名、字段名、参数名、变量名等,使用反编译工具可以还原这些信息。从Android2.3开始,Google在SDK中加入了一款叫ProGuard的Android混淆工具,ProGuard会删除这些调试信息,并用无意义的字符序列来替换类名、方法名等,使得使用反编译出来的代码难以阅读,提升逆向难度。使用ProGuard 对Android混淆过后,反编译出来的类名和方法名无法阅读,但是反编译出来的功能代码仍然是非常容易阅读的,和源代码差不多,破解者仍通过阅读功能代码来自行标记类名、方法名等,然后逆向破解。

2 Java代码混淆

通过对功能代码流程进行乱序混淆,实际运行时乱序Android混淆后的代码流程却和原始代码流程是一样的,但反编译出来的代码流程静态阅读时与原始流程有很大差异,使破解者很难通过静态分析理解代码功能,从而保护Android混淆代码不被逆向分析。比如,原始的代码流程是1->2->3->4->5->6->7,经过乱序Android混淆后静态反汇编查看到的代码流程可能变成2->7->5->1->6->4->3,实际运行时代码流程仍然是1->2->3->4->5->6->7。

3 Dalvik字节码加密
将dex文件中的部分或全部Dalvik字节码加密,Android混淆,每次需要执行时由专门的Native代码负责动态解密和回填,静态反编译出来的代码已经无法阅读甚至无法反编译,动态调试也难以逆向分析。

4 Android apk加密

Android混淆可以保证源代码的一定安全,但是并不全面。Android apk加密技术包括:DEX加壳保护,DEX指令动态加载保护和高级源码混淆保护。其中DEX加壳保护通过将DEX文件隐藏,并生成一个类似于虚像的壳文件,阻止黑客利用反编译工具获取App源码。

Android Studio下的混淆


在as下混淆安卓项目,只要在build.gradle脚本里设置 一下即可,比如我们可以这样设置:

1
2
3
4
5
6
7
8
9
buildTypes {
debug {
minifyEnabled false
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

在debug模式下,不混淆,release正式发布版本里混淆,此时用到了两个文件,一个是sdk/tools/proguard/proguard-android.txt文件, 一个是项目下的proguard-rules.pro文件。

一般情况,我们只需要修改proguard-rules.pro文件,把不需要混淆的部分在该文件中声明,因为有些类已经混淆过,。比如使用百度地图安卓sdk需要在proguard-rules.pro中加入下面代码:

1
2
3
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-dontwarn com.baidu.**

注意


  1. 使用gson,fastjsoon时,bean类不需要混淆,否则会出错,为此还特意请教了大神,哈哈。
    因为他们利用发射来解析json,混淆后找不到对应的变量导致空指针。

  2. 在android Manifest文件中的activity,service,provider, receiver,等都不能进行混淆。一些在xml中配置的view也不能进行混淆,当然,这些在sdk里默认配置文件proguard-android.txt中都有,就不用我们配置咯。

混淆后代码的调试


1 混淆之后,会给我们输出一些文件,android studio 在目录app/build/outputs/mapping下有以下文件:

  • dump.txt 描述apk文件中所有类文件间的内部结构。
  • mapping.txt 列出了原始的类,方法,和字段名与混淆后代码之间的映射,常用。
  • seeds.txt 列出了未被混淆的类和成员
  • usage.txt 列出了从apk中删除的代码

当我们发布的release版本的程序出现bug时,可以通过以上文件(特别是mapping.txt)找到错误原始的位置,进行bug修改。同时,可能一开始的proguard配置有错误,也可以通过错误日志,根据这些文件,找到哪些文件不应该混淆,从而修改proguard的配置。
注意:重新release编译后,这些文件会被覆盖,所以每发布一次程序,最好都保存一份配置文件。

2 通过mapping.txt,通过映射关系找到对应的类,方法,字段来修复bug。
这里需要利用sdk给我们提供的retrace脚本,可以将一个被混淆过的堆栈跟踪信息还原成一个可读的信息,window下时retrace.bat,linux和mac是retrace.sh,该脚本的位置在*/sdk/tools/proguard/bin/下。语法为:

1
retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]

例如:

1
./retrace.sh -verbose mapping.txt a.txt

其中的a.txt文件可以新建,然后把logcat的错误信息复制后粘贴到a.txt即可。

如果你没有指定,retrace工具会从标准输入(一般是键盘)读取。

这里有个小技巧:不用mapping也可以显示行号,避免Unknown Source

很简单,在混淆里加这么一句就可以:

1
-keepattributes SourceFile,LineNumberTable

这样,apk包会增大一些,我5.8M的包增加254K大小,还是可以接受的。

3 可以参考无源码调试:传送门——Smalidea无源码调试 android 应用

补充


20160504发现了个好文:

Android Proguard(混淆)

以及之前发现的一个 proguard 的库:

https://github.com/krschultz/android-proguard-snippets

分享是一种美德,更是一种生活方式!!

也许你会说我是一个梦想者,但我不是唯一的一个。

悦分享,越快乐^_^

欢迎交流,转载请注明出处,谢谢!

文章目錄
  1. 1. Android混淆
  2. 2. Android混淆技术
  3. 3. Android Studio下的混淆
  4. 4. 注意
  5. 5. 混淆后代码的调试
    1. 5.1. 补充
,
Fork me on GitHub