Android 代码混淆机制

Android 代码混淆机制Android代码混淆机制由于Android项目大部分用的java语言,而java属于高层抽象语言,易于反编译、反汇编,其编译后的程序包包含了大量的源代码变量、函数名、数据结构等信息,根据其编译打包后的APK文件,可以非常容易的得到近乎源代码质量的反编译代码。如果不加混淆,相当于直接将源代码拱手送人,内容严密的app权限审核可以说是形同虚设。如果大家想避免源代码泄漏后重新修改策划而额外增加的工

大家好,又见面了,我是你们的朋友全栈君。

Android 代码混淆机制

由于Android项目是基于java语言的,而java属于高层抽象语言,易于反编译,其编译后的程序包包含了大量的源代码变量、函数名、数据结构等信息,根据其编译打包后的APK文件,可以非常容易的得到 近乎源代码质量 的反编译代码。如果不加混淆,相当于直接将源代码拱手送人,内容严密的app权限审核可以说是形同虚设。如果大家想避免自己的成果被别人夺取,然后重新修改策划而额外增加的工作量,那就尽量得自己的Android项目加上混淆吧。

原理

android平台的混淆原理是把代码中原来有具体含义的包名,类名,变量名,方法名等名称全部替换成按顺序排列的无意义的英文字母a、b、c….这样代码结构没有变化,还可以运行得到一样的结果,并且就算代码被反编译出来,别人想弄懂代码的架构和具体意思也比较难。

具体方法

比较常用的方法有以下两种:

一、通过eclipse混淆代码

  • 启用代码混淆
    找到Android项目目录下的project.properties文件,如果需要对项目进行全局混码,只需要进行一步操作:将project.properties文件中的“# proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt”中的“#”去掉就可以了。

    但是如果有一些代码不能被混淆,比如引入了第三方jar文件或加入了so文件,需要调用里面的方法,那么调用JNI访问so文件的方法就不能被混码。在导出的时候,可能不会报错。但是在手机上运行的时候,需要调用so文件的时候,就会报某某方法无法找到。这个时候就需要用到proguard-project.txt。

  • 编写混淆脚本
    找到Android项目目录下的“proguard-project.txt”文件,在proguard-project.txt文件中,你需要做的就是指定混淆规则,还有指明要过滤那些文件或代码块。具体内容来看一个例子:

-ignorewarnings -optimizationpasses 7 #指定代码的压缩级别 0 - 7  -dontusemixedcaseclassnames #是否使用大小写混合 -dontskipnonpubliclibraryclasses #是否混淆第三方jar -dontpreverify #混淆时是否做预校验(可去掉加快混淆速度)  -verbose #混淆时是否记录日志(混淆后生产映射文件 map 类名 -> 转化后类名的映射  -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* #淆采用的算法  
-keep public class * extends android.app.Activity #所有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 <methods>;  #保持 native 的方法不去混淆  
}  

-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); #保持指定规则的方法不被混淆(Android layout 布局文件中为控件配置的onClick方法不能混淆)  
}  

-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*(...);  
}  

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

-keep class * implements android.os.Parcelable { #保持 Parcelable 不被混淆(aidl文件不能去混淆)      public static final android.os.Parcelable$Creator *;  
}  

-keepnames class * implements java.io.Serializable #需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)  
-keepclassmembers class * implements java.io.Serializable { #保护实现接口Serializable的类中,指定规则的类成员不被混淆      static final long serialVersionUID;  
    private static final java.io.ObjectStreamField[] serialPersistentFields;  
    !static !transient <fields>;  
    private void writeObject(java.io.ObjectOutputStream);  
    private void readObject(java.io.ObjectInputStream);  
    java.lang.Object writeReplace();  
    java.lang.Object readResolve();  
}  

-keepattributes Signature #过滤泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了)  
-keepattributes *Annotation* #假如项目中有用到注解,应加入这行配置  
-keep class **.R$* { *; } #保持R文件不被混淆,否则,你的反射是获取不到资源id的  
-keepclassmembernames class com.cgv.cn.movie.common.bean.** { *; } #转换JSON的JavaBean,类成员名称保护,使其不被混淆  
-assumenosideeffects #g过滤代码中的日志 class android.util.Log  
 {  
    public static ***  
 e(...);  
    public static ***  
 w(...);  
    public static ***  
 wtf(...);  
    public static ***  
 d(...);  
    public static ***  
 v(...);  
}  

# 下面都是项目中引入的第三方 jar包 ==== 引入jar包的绝对路径
#-libraryjars  libs/android-support-v4.jar  
#-dontwarn android.support.v4.**  
#-keep class android.support.v4.**{ *; }    
#-keep interface android.support.v4.**{*;}  
#-keep public class * extends android.support.v4.**{*;}   
#-keep public class * extends android.app.Fragment  

-libraryjars libs/armeabi-v7a/libijkffmpeg.so 
-dontwarn com.google.protobuf.nano.** -keep class com.google.protobuf.nano.**{*;} 
-dontwarn com.google.gson.** -keep class com.google.gson.**{*;} 
# 第三方统计SDK友盟相关过滤
-keepclassmembers class * { #友盟SDK中的部分代码使用,反射来调用构造函数    public <init> (org.json.JSONObject);
}  
-keep public class [com.wormhole.sdk].R$*{ #过滤R文件,友盟SDK需要引用导入工程的资源文件 public static final int *;
}

具体哪行代码是什么作用大部分上面都有注释,比较常用的有以下几点:

1.从脚本中可以看到,混淆中保留了继承自Activity、Service、Application、BroadcastReceiver、ContentProvider等基本组件。
2.保留了所有的Native变量名及类名,所有类中部分以设定了固定参数格式的构造函数,枚举等等。(详细信息请参考\examples中的例子及注释)
3.需要序列化和反序列化的类不能被混淆。(注:Java反射用到的类也不能被混淆)
4.保持R文件不被混淆,否则,你的反射是获取不到资源id的。
5.过滤引入的第三方jar包,so文件和外部lib等

//过滤第三方jar包,com.google.gson替换成要想要过滤的包名
-dontwarn com.google.gson.**
-keep class com.google.gson.**{*;} 
//过滤so文件,libs/armeabi-v7a/libijkffmpeg.so换成想过滤的搜文件路径
-libraryjars  libs/armeabi-v7a/libijkffmpeg.so
  • 打包测试
    编写完混淆脚本后就可以直接用eclipse签名打包出APK文件了,但是有时候可能有混淆脚本有错误或遗漏,导致打包失败的情况,这时候就得检查混淆文件哪里出了错。还有一种情况是可以正常打包出APK文件,但是不一定能运行,能运行也会在某一步上出错,这种情况一般是因为把代码中不可混淆的字段或文件给混淆了比如引入的jar包和so文件等,导致程序功能变化。

二、通过ProGuard工具混淆代码

如果你想把你的Android项目打包成jar文件然后再混淆,那这种方法比较适合

  • 下载运行ProGuard工具
    1.首先到http://proguard.sourceforge.net/下载proguard,目前我下载并使用的是proguard5.1
    2.解压proguard5.1,执行 bin目录下的proguardgui.bat文件打开ProGuard工具
  • 从Android项目到处jar包
    笔者是通过eclipse来到处Android项目jar包的,用Android Studio来做也差不多,这就不过多介绍了。
    eclipse中右键点击项目Export–>Java–>JAR file–>Next,然后出现如下界面

这里写图片描述

只需要选择java文件即可,其他配置文件什么的都不用选择

  • 配置ProGuard工具
    1.打开ProGuard工具,点击左边“input/output”菜单,然后点击右边的“Add input”按钮,添加需要混淆的jar包,我这里是test.jar,然后点击“add output”,选择输出的路径和包名。
    这里写图片描述
    2.添加支持库,这个地方很重要,很多同学刚开始使用这个工具的时候就是这里老是出问题。点击右边的“add”。
    这里写图片描述
    这里需要注意一下,最好把你的eclipse里java project里的libraries所有Library的jar包,包含web项目lib下面的包,jdk中jre下面的包和servlet.jar包等copy到一个目录,然后在这里加入这些jar包。系统默认会带上rt.jar,这里我们可以先remove掉,然后到jre下面copy所有的包。
    3.切换左侧的“shrinking”,obfuscation”和“optimization”等标签来设置你所需要的混淆规则。
    4.点击information,设置如图所示,注意选择jdk版本(Target选项)。
    5.点击“process”,再点击“save configuration”,在弹出的对话框中,输入要保存的配置文件名称,最后点击“保存”。

至此就完成了jar文件的混淆,并保存了混淆文件。
当然,如果你已经写好的混淆文件,那么直接通过导入混淆文件进行混淆就行了。具体操作如下:
1.打开progrard目录,执行 bin目录下的proguardgui.bat。
2.点击第一个选项“Proguard”,再点击“Load configuration”,选择你的混淆文件进行加载。
3.然后点击Process,然后点击View configuration查看是否是已经修改过后的配置文件。

  • 检测测试混淆后的jar文件
    如果混淆过程中出错,可以在View configuration查看错误日志,然后直接通过文本编辑器打开混淆配置文件,然后进行相应修改。

Ending

好了,至此已经把我所了解的Android混淆机制及使用方法介绍完毕,如果有错误的地方或者有不明了之处请大家留言指出。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/139104.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Win10 桌面美化

    Win10 桌面美化Win10桌面美化最近发现了几款Win10界面美化的软件,看了看别人家的Win10操作界面,瞬间觉得自己的low了,关键是赏心悦目啊!废话不多说,先看看我原来桌面和美化后的桌面对比图原始桌面美化桌面1.安装RocketDockRocketDock可以提供类似macos的操作系统图标特效,打开安装包进行安装,完毕后启动得到效果如下:可以发现切换效果与mac类似,他默认的主题是C…

    2022年4月25日
    52
  • AP模式和Router模式区别是什么

    AP模式和Router模式区别是什么AP模式和Router模式有什么区别呢?在TP-Link、水星(Mercury)、迅捷(Fast)等品牌的迷你无线路由器上,有AP模式、Router模式、中继和桥接等几个上网模式,本文重点详细介绍AP模式与Router模式的区别。AP(接入点)模式在AP模式下,需要把迷你无线路由器接入到已经可以上网的路由器或者交换机上面,然后迷你无线路由器可以提供无线WiFi,一般的迷你无线路由器出厂

    2025年8月2日
    2
  • 物联网架构及五大通信协议是什么_物联网不能实现哪种通信方式

    物联网架构及五大通信协议是什么_物联网不能实现哪种通信方式消息触达能力是物联网(internetofthings,IOT)的重要支撑,而物联网很多技术都源于移动互联网。柳猫将阐述移动互联网消息推送技术在物联网中的应用和演进。一、物联网架构和关键技术从开发的角度,无线接入是物联网设备端的核心技术,身份设备管理和消息推送技术是物联网云端的核心技术。而从场景体验的角度,除了前者,还要包括手机的前端开发技术。IP互联架构已是物联网的事实标准(有关物联网TCP/IP层关键技术将另文阐述,敬请关注)。本文所讲的消息推送技术是基于TCP/I…

    2022年9月18日
    2
  • python ssh连接_pycharm显示no module named

    python ssh连接_pycharm显示no module named文章目录报错问题分析解决方案1.把id_rsa转换成PuTTY2.id_rsa转换成RSA参考报错在Pycharm中用密钥登录的时候会报错[1/4/202110:54AM]Uploadtogpu11-188failed:keypair‘C:\Users\xx.ssh\id_rsa’iscorruptorhasunknownformat.OnlySSH2keysinOpenSSHformat(DSA,RSAorECDSA)orPuT

    2022年8月27日
    4
  • Linux运维必备技能:如何在 Vim 中删除多行?

    Linux运维必备技能:如何在 Vim 中删除多行?我们都会犯错,犯错是人之常情,改进它也很重要。如果你在Vim中出错,你可以dw在普通模式下使用删除一个单词。您键入dd它会删除当前行。如果要在Vim中删除多行,可以使用相同的ddVim命令,将行数添加到该命令中。因此,10dd将从光标底部删除10行(包括光标所在的行)。让我们详细了解如何在以效率着称的编辑器中删除一行或多行。删除单行以下是在Vim中删除单行文本的步骤:按Escape(Esc)键进入Normal模式确保光标位于要删除的行上。快速按下dd这

    2022年6月18日
    30
  • request.getattribute()用法_getrequesturl

    request.getattribute()用法_getrequesturlpackageliuliking;importjava.io.IOException;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.Http

    2022年9月24日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号