APK的混淆与反编译

来源:互联网 发布:ubuntu 安装sublime 编辑:程序博客网 时间:2024/05/04 06:32

第 一章 APK反编译

在线反编译:http://www.ludaima.cn/android.html

原文链接:http://blog.csdn.net/vipzjyno1/article/details/21039349/

1.1 反编译工具

使用工具:

Ø  Android反编译整合工具包(最新) 下载

http://download.csdn.net/detail/uu00soldier/9739808

Ø  官方最新版本下载地址:

1)   apktool(googlecode)

https://ibotpeaches.github.io/Apktool/

2)   dex2jar(google code)

https://github.com/pxb1988/dex2jar

3)   jd-gui(googlecode)最新版请见官方

https://code.google.com/archive/p/innlab/downloads

工具介绍:

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 代码混淆

混淆官方说明:https://developer.android.com/studio/build/shrink-code.html

混淆的教程:http://blog.csdn.net/u011889786/article/details/50945693

此教程里面讲得非常详细,各个参数、用法都有非常详细的解释。

参考资料:

简书:http://www.jianshu.com/p/e19cc5194a31

微信:https://mp.weixin.qq.com/s/ZqV3xrxjM8pFiidDEP7A2w

所给出的这三篇文章把代码混淆的方法、步骤已经讲得很清楚了,这里就不再多说了。

代码混淆分三个基本步骤:

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.csdn.net/jiangwei0910410003/article/details/48415225/

加固都用爱加密、360等在线的加固手段,以上这个博客把加壳、脱壳的原理详细的描述了一遍,利于自己实现自己的加壳机制,明白原理。


0 0
原创粉丝点击