混淆编译

为了保护APK代码和架构,不轻易被外部人员反编译和破解,对发布的APK,所以必须进行代码混淆编译。
Java 是一种跨平台的、解释型语言,Java 源代码(.java文件)编译成中间“字节码”存储于.class 文件中。由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成Java 源代码。为了防止这种现象,我们可以使用Java 混淆器对 Java 字节码进行混淆。

Android目前采用开源混淆工具ProGuard来进行混淆编译。以下介绍一下如何在Android Studio下进行混淆编译。


1、在工程目录下找到proguard-rules.pro文件,它就是你要进行编写混淆配置的文件


2、修改混淆文件,下面提供一份混淆的模板。

-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;                                                            # 保持自己定义的类不被混淆

上面是最基础的配置。一般还不够,因为你的项目总免不了用第三方库或者jar包,如果不能正确的混淆第三方资源,可能导致你的应用无法使用。
下面贴出常用的第三方混淆部分。

#如果有引用v4包可以添加下面这行
-keep class android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v4.**
-keep public class * extends android.app.Fragment  #如果引用了v4或者v7包,可以忽略警告,因为用不到android.support
-dontwarn android.support.**  #保持自定义组件不被混淆
-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*(...);
}  #保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable  #保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {  static final long serialVersionUID;  private static final java.io.ObjectStreamField[] serialPersistentFields;  private void writeObject(java.io.ObjectOutputStream);  private void readObject(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>;
#}  #xUtils(保持注解,及使用注解的Activity不被混淆,不然会影响Activity中你使用注解相关的代码无法使用)
-keep class * extends java.lang.annotation.Annotation {*;}
-keep class com.otb.designerassist.activity.** {*;}  #自己项目特殊处理代码(这些地方我使用了Gson类库和注解,所以不希望被混淆,以免影响程序)
-keep class com.otb.designerassist.entity.** {*;}
-keep class com.otb.designerassist.http.rspdata.** {*;}
-keep class com.otb.designerassist.service.** {*;}  ##混淆保护自己项目的部分代码以及引用的第三方jar包library(想混淆去掉"#")
#-libraryjars libs/umeng-analytics-v5.2.4.jar
#-libraryjars libs/alipaysecsdk.jar
#-libraryjars libs/alipayutdid.jar
#-libraryjars libs/weibosdkcore.jar   # 以libaray的形式引用的图片加载框架,不想混淆(注意,此处不是jar包形式,想混淆去掉"#")
#-keep class com.nostra13.universalimageloader.** { *; }  ###-------- Gson 相关的混淆配置--------
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }  ###-------- pulltorefresh 相关的混淆配置---------
-dontwarn com.handmark.pulltorefresh.library.**
-keep class com.handmark.pulltorefresh.library.** { *;}
-dontwarn com.handmark.pulltorefresh.library.extras.**
-keep class com.handmark.pulltorefresh.library.extras.** { *;}
-dontwarn com.handmark.pulltorefresh.library.internal.**
-keep class com.handmark.pulltorefresh.library.internal.** { *;}  ###---------  reservoir 相关的混淆配置-------
-keep class com.anupcowkur.reservoir.** { *;}  ###-------- ShareSDK 相关的混淆配置---------
-keep class cn.sharesdk.** { *; }
-keep class com.sina.sso.** { *; }  ###--------------umeng 相关的混淆配置-----------
-keep class com.umeng.** { *; }
-keep class com.umeng.analytics.** { *; }
-keep class com.umeng.common.** { *; }
-keep class com.umeng.newxp.** { *; }  

3、修改build.gradle文件

将release节点下,minifyEnabled设置为true。


4、导出APK文件
Android Studio菜单Build->Generate Signed APK。。。具体就不说了。

打包发布软件时务必保留APK的同时附带此次编译时生成的mapping.txt文件。如果程序发生错误或者需要查看log,可利用mapping文件和Android sdk自带工具进行反混淆,从而得出原有的类名、方法名,才能定位log的问题,否则经过混淆的log将无法阅读,会给维护和调试造成灾难性的后果。

还有一种叫系统签名的东西,如果apk需要调用系统权限的api时,则需要对apk进行系统签名。


反混淆

在SDK的安装目录下\tools\proguard\lib找到proguardgui,双击进入ProGuard工具,点击ReTrace按钮,将mapping文件和log信息导进去,点击ReTrace!就可以看到log的错误信息。


反编译

这里反编译用的APK文件是自己写的一个Demo,这个Demo里面的代码很简单,只有一个Button,点击将弹出一个Toast。代码如下。

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btn_test = (Button) findViewById(R.id.btn_test);btn_test.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(MainActivity.this,"点击了Button!!",Toast.LENGTH_SHORT).show();}});}
}

activity_main.xml中的资源如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><Button
        android:id="@+id/btn_test"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="测试" />
</RelativeLayout>

将代码打成一个APK包,并命名成Demo.apk。

接下来就开始对这个Demo程序进行反编译了。

要想将APK文件中的代码反编译出来,我们需要用到以下两款工具:

  • dex2jar 这个工具用于将dex文件转换成jar文件
    下载地址:http://sourceforge.net/projects/dex2jar/files/
  • jd-gui 这个工具用于将jar文件转换成java代码
    下载地址:http://jd.benow.ca/

将这两个工具都下载好并解压,然后我们就开始对Demo程序进行反编译。

解压dex2jar压缩包后,你会发现有很多个文件,如下图所示:

我们要用到的是d2j-dex2jar.bat这个文件,当然如果你是linux或mac系统的话就要用d2j-dex2jar.sh这个文件。

然后我们将Demo.apk文件也进行解压,先将文件重命名成Demo.zip,然后用解压软件打开。解压之后你会发现里面有一个classes.dex文件。

这个classes.dex文件就是存放所有java代码的地方了,我们将它拷贝到dex2jar解压后的目录下,并在cmd中也进入到同样的目录,然后执行:

d2j-dex2jar classes.dex

执行结果如下:

没有报任何错误,这就说明我们已经转换成功了。现在观察dex2jar目录,你会发现多了一个文件,如下图所示:

可以看到,classes-dex2jar.jar这个文件就是我们借助工具之后成功转换出来的jar文件了。但是对于我们而言,jar文件也不是可读的,因此这里还需要再借助一下jd-gui这个工具来将jar文件转换成java代码。

下面就很简单了,使用jd-gui工具打开classes-dex2jar.jar这个文件,结果如下图所示:

可以看到,我们的代码反编译工作已经成功了,MainActivity中的代码非常清晰,基本已经做到了90%以上的还原工作。但是如果想要做到100%的代码还原还是非常有难度的,因为像setContentView()方法传入的参数,其实就是一个资源的id值而已,那么这里反编译也就只能将相应的id值进行还原,而无法变成像R.layout.activity_main这样直观的代码展示。

另外,除了MainActivity之外,还有很多其它的代码也被反编译出来了,因为当前项目有引用support-v4和support-v7的包,这些引用的library也会作为代码的一部分被打包到classes.dex文件当中,因此反编译的时候这些代码也会一起被还原。


接下来我们看一下如何反编译资源。
其实刚才Demo.apk的解压目录当中已经有资源文件了,有AndroidManifest.xml文件,也有res目录。进入res目录当中,内容如下图所示:

这不是所有资源文件都在这里了么?其实这些资源文件都是在打包的时候被编译过了,我们直接打开的话是看不到明文的。都是些乱码。

直接对APK包进行解压是无法得到它的原始资源文件的,因此我们还需要对资源进行反编译才行。
要想将APK文件中的资源反编译出来,又要用到另外一个工具了:

  • apktool 这个工具用于最大幅度地还原APK文件中的9-patch图片、布局、字符串等等一系列的资源。
    下载地址:http://ibotpeaches.github.io/Apktool/install/

我们需要的就是apktool.bat和apktool.jar这两个文件。目前apktool.jar的最新版本是2.2.0,这里我就下载最新的了,然后将apktool_2.2.0.jar重命名成apktool.jar,并将它们放到同一个文件夹下就可以了,如下图所示:

然后我们将Demo.apk拷贝到和这两个文件同样的目录当中,然后cmd也进入到这个目录下,并在cmd中执行如下命令:

apktool d Demo.apk

其中d是decode的意思,表示我们要对Demo.apk这个文件进行解码。那除了这个基本用法之外,我们还可以再加上一些附加参数来控制decode的更多行为:

  • f 如果目标文件夹已存在,则强制删除现有文件夹(默认如果目标文件夹已存在,则解码失败)。
  • o 指定解码目标文件夹的名称(默认使用APK文件的名字来命名目标文件夹)。
  • s 不反编译dex文件,也就是说classes.dex文件会被保留(默认会将dex文件解码成smali文件)。
  • r 不反编译资源文件,也就是说resources.arsc文件会被保留(默认会将resources.arsc解码成具体的资源文件)。
    常用用法就这么多了,那么上述命令的执行结果如下图所示:

这就说明反编译资源已经成功了。

当然你也有可能反编译失败,原因很有可能是你之前使用过apktool的老版本进行过反编译操作,然后apktool就会在你系统的C:\Users\Administrator\apktool\framework这个目录下生成一个名字为1.apk的缓存文件,将这个缓存文件删除掉,然后再重新执行反编译命令应该就可以成功了。

现在你会发现在当前目录下多了一个Demo文件夹,这个文件夹中存放的就是反编译的结果了。我们可以打开AndroidManifest.xml来瞧一瞧,如下图所示:

你可以再到其它目录中去看一看别的资源,基本上都是可以正常还原的,这样我们就把反编译资源的方法也已经掌握了。


我们再来看一下通过apktool反编译后的包目录情况,如下图所示:

其中,original文件夹下存放的是未经反编译过、原始的AndroidManifest.xml文件,res文件夹下存放的是反编译出来的所有资源,smali文件夹下存放的是反编译出来的所有代码,AndroidManifest.xml则是经过反编译还原后的manifest文件。这里值得一提的是smali文件夹,如果你进入到这个文件夹中你会发现它的目录结构和我们源码中src的目录结构是几乎一样的,主要的区别就是所有的java文件都变成了smali文件。smali文件其实也是真正的源代码,只不过它的语法和java完全不同,它有点类似于汇编的语法,是Android虚拟机所使用的寄存器语言,语法结构大概如下所示:

看上去有点懵逼,但是如果你一旦能够看得懂smali文件的话,那么你就可以做很恐怖的事情了——你可以随意修改应用程序内的逻辑,将其进行破解!

我也没有怎么去了解,关于smali的语法,网上的资料也非常多,如果你感兴趣的话可以直接上网去搜,这里我只是简单提一下。

Android混淆编译、反混淆、反编译相关推荐

  1. Android安全攻防战,反编译与混淆技术完全解析

    之前一直有犹豫过要不要写这篇文章,毕竟去反编译人家的程序并不是什么值得骄傲的事情.不过单纯从技术角度上来讲,掌握反编译功能确实是一项非常有用的技能,可能平常不太会用得到,但是一旦真的需要用到的了,而你 ...

  2. .net 编译、反编译、查壳、脱壳、反混淆工具

    https://tools.pediy.com/win/dotnet.htm .NET Reflector & Reflexil 反编译工具,支持修改il代码 ILSpy 反编译工具,支持调试 ...

  3. Powerbuilder混淆与加密器(powerbuilder防止反编译,pb混淆器,支持5-12) obfuscator for PowerBuilder...

    正式版购买请参考:http://www.mis2erp.com http://www.pb-obfuscator.com http://www.pbd-obfuscator.com 下载地址:http ...

  4. android 反注册代码,Android程序反混淆利器——Simplify工具

    本帖最后由 Regan_MX 于 2017-1-25 10:30 编辑 文章难易度:★★★ 文章阅读点/知识点:Android程序反混淆利器 文章作者:desword文章来源:安全客 [技术分享]An ...

  5. Android聚合SDK母包反编译出包教程

    文章目录 [前言] 一.SDK预处理 1.SDK资源合并 1.1.合并res目录下的资源 1.2.合并libs目录 1.3.合并assets目录 1.4.合并AndroidManifest.xml 1 ...

  6. android php 项目代码混淆,Android Studio配置反混淆的实现

    Android Studio如何混淆 为什么要混淆 了解安卓程序编译的会知道 其实我们的apk并不是很安全,从apk从可以解包出,步骤: 将apk文件改成zip结尾 然后解压zip 然后就会发现里面有 ...

  7. Android:代码混淆反混淆

    当我们的线上代码crash的时候,获取到的crash信息是混淆后的, 我们可以通过android 自带的工具对混淆crash信息进行反混淆. 可以使用<SDK目录>\tools\progu ...

  8. Android TV下LeanbackLauncher的反编译,AS重新打包修改

    本文介绍Android 7.1平台下Google LeanbakLauncher的反编译流程,并使用AS工具重新打包修改. 最近需要开发一款TV桌面应用,调研了各类桌面,如当贝桌面,小米桌面,开源的猫 ...

  9. (android实战)第三方应用反编译并修改UI信息后,重新编译

    在实际开发过程中,我们会看到好的第三方效果,羡慕不以,就想如何能看到被人的UI布局,下面就是如何对第三方应用进行反编译,并重新编译的全过程 第一步 下载android-apktool 下载路径:htt ...

最新文章

  1. 【跃迁之路】【725天】程序员高效学习方法论探索系列(实验阶段482-2019.2.15)...
  2. cmd指令大全指令_Linux 超全实用指令大全 | CSDN 博文精选
  3. Bat 循環執行範例
  4. 【pytorch速成】Pytorch图像分类从模型自定义到测试
  5. android lame wav 转 mp3,Android JNI Lame编解码实现wav到MP3的转换
  6. 众辰变频器参数设定_变频器被加密了怎么办?这20个品牌都可以解密
  7. 关于Struts2中的值栈与OGNL表达式
  8. 手机在线运行python_让Python程序在线执行
  9. 小米线刷一直显示flashing_小米空调质量怎么样 小米空调一晚上多少电 看完这篇你就有数了...
  10. 使用matlab进行深度学习
  11. XAMPP汉化教程指南
  12. windows域与工作组概念
  13. 逃离北上广的成本越来越高了
  14. Adobe ColdFusion
  15. 基于深度学习的新闻摘要生成算法实现与详解(Encoder-Decoder框架模型)
  16. 计算机颜色显示器,电脑显示器怎么选,看这一篇就够了
  17. 数据结构算法之数组篇
  18. 实操《深入浅出React和Redux》第四期--react-redux
  19. 仿写微信公众号添加自定义菜单 并给后台存数据
  20. 研究方向三选一选择FPGA/计算机视觉/故障检测

热门文章

  1. 新型UVC+UVA紫外线口罩消毒器-疫情防护+环境保护
  2. PostgreSQL 15 preview -:你了解PostgreSQL GUC 参数吗?
  3. Bottle 中文文档
  4. 【供应链架构day6】百世零售供应链架构之道:全渠道的落地与挑战
  5. Shell脚本语法3.21
  6. 基于Web的校园跑腿管理系统的设计与实现
  7. Remove Duplicate
  8. java使用poi-tl操作word文件
  9. 工作5年观察:快速在职场崛起,拼这10个认知
  10. Codeforces1244C 数学