Android APK的混淆与反编译
第 一章 APK反编译
在线反编译:http://www.ludaima.cn/android.html
原文链接:http://blog.****.net/vipzjyno1/article/details/21039349/
1.1 反编译工具
使用工具:
Ø Android反编译整合工具包(最新) 下载
http://download.****.net/detail/uu00soldier/9739808
Ø 官方最新版本下载地址:
1) apktool(googlecode)
2) dex2jar(google code)
工具介绍:
apktool 作用:资源文件获取,可以提取出图片文件和布局文件进行使用查看
dex2jar 作用:将apk反编译成Java源码(classes.dex转化成jar文件)
jd-gui 作用:查看APK中classes.dex转化成出的jar文件,即源码文件
1.2 反编译方法
反编译分为两个部分,这两个部分是独立的影响。
1、 获取项目中的图片、XML配置、特效语言资源等文件,其他的可以通过直接解压的方式来获取,但是XML里面的布局配置文件,必须通过这个工具来进行解压读取,不然获取到的XML布局文件里面打开全部是乱码。
2、 获取Java代码文件,这是反编译的主要目的,借鉴别人的设计思路,获取第三方jar包等。
1.2.1 获取APK中资源文件
通过反编译得到程序的源代码、图片、XML配置、语言资源等文件,下载上述工具中的apktool,解压得到3个文件:aapt.exe,apktool.bat,apktool.jar;将需要反编译的APK文件放到该目录下,打开命令行界面(运行CMD) ,定位到apktool文件夹,输入以下命令:
apktool.bat d –f test.apk -o test
(命令中test.apk指的是要反编译的APK文件全名,test为反编译后资源文件存放的目录名称,即为:apktool.bat d -f [apk文件 ] -o [输出文件夹] )
说明获取成功,之后发现在文件夹下多了个test文件,点击便可以查看该应用的所有资源文件了。如果你想将反编译完的文件重新打包成apk,那你可以:输入:apktool.bat b test(你编译出来文件夹)便可,效果如下:
之后在之前的test文件下便可以发现多了2个文件夹:
build
dist(里面存放着打包出来的APK文件)
1.2.2 反编译得到Java源代码
下载上述工具中的dex2jar和jd-gui ,解压将要反编译的APK后缀名改为.rar或则 .zip,并解压,得到其中的额classes.dex文件(它就是java文件编译再通过dx工具打包而成的),将获取到的classes.dex放到之前解压出来的工具dex2jar-0.0.9.15 文件夹内,在命令行下定位到dex2jar.bat所在目录,输入dex2jar.bat classes.dex,效果如下:
在该目录下会生成一个classes_dex2jar.jar的文件,然后打开工具jd-gui文件夹里的jd-gui.exe,之后用该工具打开之前生成的classes_dex2jar.jar文件,便可以看到源码了,效果如下:
被混淆过的效果图(类文件名称以及里面的方法名称都会以a,b,c....之类的样式命名):
第 二章 混淆加壳
2.1 代码混淆
混淆的教程:http://blog.****.net/u011889786/article/details/50945693
此教程里面讲得非常详细,各个参数、用法都有非常详细的解释。
参考资料:简书:http://www.jianshu.com/p/e19cc5194a31
所给出的这三篇文章把代码混淆的方法、步骤已经讲得很清楚了,这里就不再多说了。
代码混淆分三个基本步骤:
1、 加入基本混淆项
2、 针对该工程的混淆项
3、 针对第三方库的解决
2.1.1 参数说明
proguard中一共有三组六个keep关键字,说明如下:
关键字 |
描述 |
keep |
保留类和类中的成员,防止它们被混淆或移除。 |
keepnames |
保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。 |
keepclassmembers |
只保留类中的成员,防止它们被混淆或移除。 |
keepclassmembernames |
只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。 |
keepclasseswithmembers |
保留类和类中的成员,防止它们被混淆或移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。 |
keepclasseswithmembernames |
保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。 |
Proguard中通配符的说明:
通配符 |
描述 |
<field> |
匹配类中的所有字段 |
<method> |
匹配类中的所有方法 |
<init> |
匹配类中的所有构造函数 |
* |
匹配任意长度字符,但不含包名分隔符(.)。比如说我们的完整类名是com.example.test.MyActivity,使用com.*,或者com.exmaple.*都是无法匹配的,因为*无法匹配包名中的分隔符,正确的匹配方式是com.exmaple.*.*,或者com.exmaple.test.*,这些都是可以的。但如果你不写任何其它内容,只有一个*,那就表示匹配所有的东西。 |
** |
匹配任意长度字符,并且包含包名分隔符(.)。比如proguard-android.txt中使用的-dontwarn android.support.**就可以匹配android.support包下的所有内容,包括任意长度的子包。 |
*** |
匹配任意参数类型。比如void set*(***)就能匹配任意传入的参数类型,*** get*()就能匹配任意返回值的类型。 |
… |
匹配任意长度的任意类型参数。比如void test(…)就能匹配任意void test(String a)或者是void test(int a, String b)这些方法。 |
2.1.2 混淆模板
代码混淆的基本模板,其他项目的混淆可以以此为模板,在此基础上添加对应的特定要求。
#下面是常见的proguard.cfg配置项
#指定代码的压缩级别
-optimizationpasses5
#包名不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
# 指定不去忽略非公共的库的类的成员
-dontskipnonpubliclibraryclassmembers
#优化 不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解 -keepattributes *Annotation*
#忽略警告
-ignorewarning
##记录生成的日志数据,gradle build时在本项目根目录输出##
#apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员 -printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射-printmapping mapping.txt
########记录生成的日志数据,gradle build时 在本项目根目录输出-end#####
#需要保留的东西
# 保持哪些类不被混淆
-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 * extendsandroid.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.**
-keep public classcom.android.vending.licensing.ILicensingService
##########JS接口类不混淆,否则执行不了
-dontwarn com.android.JsInterface.**
-keep class com.android.JsInterface.** {*;}
#极光推送和百度lbs android sdk一起使用proguard 混淆的问题#http的类被混淆后,导致apk定位失败,保持apache 的http类不被混淆就好了
-dontwarn org.apache.**
-keep class org.apache.**{ *;}
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context,android.util.AttributeSet);
public<init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
#保持 native 方法不被混淆
-keepclasseswithmembernamesclass * {
native <methods>;
}
#保持自定义控件类不被混淆
-keepclasseswithmembersclass * {
public <init>(android.content.Context, android.util.AttributeSet);
}
#保持自定义控件类不被混淆
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
#保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable
#保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static finaljava.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private voidwriteObject(java.io.ObjectOutputStream);
private voidreadObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#保持枚举 enum 类不被混淆 如果混淆报错,建议直接使用上面的-keepclassmembers class * implements java.io.Serializable即可
-keepclassmembers enum * {
public static **[] values();
public static **valueOf(java.lang.String);
}
-keepclassmembers class * {
public void *ButtonClicked(android.view.View);
}
#不混淆资源类
-keepclassmembers class **.R$* {
public static <fields>;
}
#避免混淆泛型 如果混淆报错建议关掉
#–keepattributes Signature
######混淆保护自己项目的部分代码以及引用的第三方jar包library########
#如果引用了v4或者v7包
-dontwarn android.support.**
#如果有引用v4包可以添加下面这行
-keep public class * extendsandroid.support.v4.app.Fragment
#如果用到Gson解析包的,直接添加下面这几行就能成功混淆,不然会报错
#gson -libraryjars libs/gson-2.2.2.jar
-keepattributes Signature
# Gson specific classes
-keep class sun.misc.Unsafe { *;}
# Application classes that will beserialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *;}
#客户端代码中的JavaBean(实体类)的类名与其字段名称全部变成了a、b、c、d等等字符串,
#这与服务端返回的json字符串中的不一致,导致解析失败。所以,解决的办法是:在进行混淆编译进行打包apk的时候,
#过滤掉存放所有JavaBean(实体类)的包不进行混淆编译
-keep class com.android.model.** {*;}
####混淆保护自己项目的部分代码以及引用的第三方jar包library-end####
2.2 APK加固
加固实现方案及原理:http://blog.****.net/jiangwei0910410003/article/details/48415225/
加固都用爱加密、360等在线的加固手段,以上这个博客把加壳、脱壳的原理详细的描述了一遍,利于自己实现自己的加壳机制,明白原理。