Android 编程下的代码混淆proguard

2024-02-24 05:38

本文主要是介绍Android 编程下的代码混淆proguard,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android 编程下的代码混淆proguard

简介

Java代码是非常容易反编译的。为了很好的保护Java源代码,我们往往会对编译好的class文件进行混淆处理。

ProGuard是一个混淆代码的开源项目。它的主要作用就是混淆,当然它还能对字节码进行缩减体积、优化等,但那些对于我们来说都算是次要的功能。官网网址是:

http://proguard.sourceforge.net/

详解


1、原理

Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码。为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆。

混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。被混淆过的程序代码,仍然遵照原来的档案格式和指令集,执行结果也与混淆前一样,只是混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,在缺乏相应的函数名和程序注释的况下,即使被反编译,也将难以阅读。同时混淆是不可逆的,在混淆的过程中一些不影响正常运行的信息将永久丢失,这些信息的丢失使程序变得更加难以理解。

混淆器的作用不仅仅是保护代码,它也有精简编译后程序大小的作用。由于以上介绍的缩短变量和函数名以及丢失部分信息的原因, 编译后 jar 文件体积大约能减少25% ,这对当前费用较贵的无线网络传输是有一定意义的。

2、语法
-include {filename}							#从给定的文件中读取配置参数   
-basedirectory {directoryname}    					#指定基础目录为以后相对的档案名称   
-injars {class_path}    						#指定要处理的应用程序jar,war,ear和目录   
-outjars {class_path}    						#指定处理完后要输出的jar,war,ear和目录的名称   
-libraryjars {classpath}    						#指定要处理的应用程序jar,war,ear和目录所需要的程序库文件   
-dontskipnonpubliclibraryclasses    					#指定不去忽略非公共的库类。   
-dontskipnonpubliclibraryclassmembers    				#指定不去忽略包可见的库类的成员。  #保留选项   
-keep {Modifier} {class_specification}    				#保护指定的类文件和类的成员   
-keepclassmembers {modifier} {class_specification}    <span style="white-space:pre">		</span>	#保护指定类的成员,如果此类受到保护他们会保护的更好  
-keepclasseswithmembers {class_specification}    		#保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。   
-keepnames {class_specification}    					#保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)   
-keepclassmembernames {class_specification}    			#保护指定的类的成员的名称(如果他们不会压缩步骤中删除)   
-keepclasseswithmembernames {class_specification}    	#保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)   
-printseeds {filename}    						#列出类和类的成员-keep选项的清单,标准输出到给定的文件   #压缩   
-dontshrink    								#不压缩输入的类文件   
-printusage {filename}   
-whyareyoukeeping {class_specification}       #优化   
-dontoptimize    							#不优化输入的类文件   
-assumenosideeffects {class_specification}    			<span style="white-space:pre">	</span>#优化时假设指定的方法,没有任何副作用   
-allowaccessmodification    						#优化时允许访问并修改有修饰符的类和类的成员   #混淆   
-dontobfuscate    							#不混淆输入的类文件   
-printmapping {filename}   
-applymapping {filename}    						#重用映射增加混淆   
-obfuscationdictionary {filename}    					#使用给定文件中的关键字作为要混淆方法的名称   
-overloadaggressively    						#混淆时应用侵入式重载   
-useuniqueclassmembernames    						#确定统一的混淆类的成员名称来增加混淆   
-flattenpackagehierarchy {package_name}    				#重新包装所有重命名的包并放在给定的单一包中   
-repackageclass {package_name}    					#重新包装所有重命名的类文件中放在给定的单一包中   
-dontusemixedcaseclassnames    					#混淆时不会产生形形色色的类名   
-keepattributes {attribute_name,...}    #保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and   InnerClasses.   
-renamesourcefileattribute {string}    					#设置源文件中给定的字符串常量  

demo 实例

# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html# Add any project specific keep options here:# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*-keepattributes *Annotation*
-keepattributes Signature-libraryjars libs/apns_1.0.6.jar
-libraryjars libs/armeabi/libBaiduMapSDK_v2_3_1.so
-libraryjars libs/armeabi/liblocSDK4.so
-libraryjars libs/baidumapapi_v2_3_1.jar
-libraryjars libs/core.jar
-libraryjars libs/gesture-imageview.jar
-libraryjars libs/gson-2.0.jar
-libraryjars libs/infogracesound.jar
-libraryjars libs/locSDK_4.0.jar
-libraryjars libs/ormlite-android-4.48.jar
-libraryjars libs/ormlite-core-4.48.jar
-libraryjars libs/universal-image-loader-1.9.0.jar-keep class com.baidu.** { *; } 
-keep class vi.com.gdi.bgl.android.**{*;}-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 * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.**
-keep public class com.android.vending.licensing.ILicensingService-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.uuhelper.Application.** { *; }
-keep class net.sourceforge.zbar.** { *; }
-keep class com.google.android.gms.** { *; } -keep class com.bank.pingan.model.** { *; }-keep public class * extends com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper
-keep public class * extends com.j256.ormlite.android.apptools.OpenHelperManager-keep class com.android.vending.licensing.ILicensingService
-keep class android.support.v4.** { *; }  
-keep class org.apache.commons.net.** { *; }  
-keep class com.tencent.** { *; }  -keep class com.umeng.** { *; }  
-keep class com.umeng.analytics.** { *; }  
-keep class com.umeng.common.** { *; }  
-keep class com.umeng.newxp.** { *; }  -keep class com.j256.ormlite.** { *; }  
-keep class com.j256.ormlite.android.** { *; }  
-keep class com.j256.ormlite.field.** { *; }  
-keep class com.j256.ormlite.stmt.** { *; } -dontwarn android.support.v4.**  
-dontwarn org.apache.commons.net.** 
-dontwarn com.tencent.**  -keepclasseswithmembernames class * {native <methods>;
}-keepclasseswithmembernames class * {public <init>(android.content.Context, android.util.AttributeSet);
}-keepclasseswithmembernames class * {public <init>(android.content.Context, android.util.AttributeSet, int);
}-keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);
}-keep class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator *;
}-keepclasseswithmembers class * {public <init>(android.content.Context);
}-dontshrink
-dontoptimize
-dontwarn com.google.android.maps.**
-dontwarn android.webkit.WebView
-dontwarn com.umeng.**
-dontwarn com.tencent.weibo.sdk.**
-dontwarn com.facebook.**-keep enum com.facebook.**
-keepattributes Exceptions,InnerClasses,Signature
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable-keep public interface com.facebook.**
-keep public interface com.tencent.**
-keep public interface com.umeng.socialize.**
-keep public interface com.umeng.socialize.sensor.**
-keep public interface com.umeng.scrshot.**-keep public class com.umeng.socialize.* {*;}
-keep public class javax.**
-keep public class android.webkit.**-keep class com.facebook.**
-keep class com.umeng.scrshot.**
-keep public class com.tencent.** {*;}
-keep class com.umeng.socialize.sensor.**-keep class com.tencent.mm.sdk.openapi.WXMediaMessage {*;}-keep class com.tencent.mm.sdk.openapi.** implements com.tencent.mm.sdk.openapi.WXMediaMessage$IMediaObject {*;}-keep class im.yixin.sdk.api.YXMessage {*;}
-keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;}-keep public class [your_pkg].R$*{public static final int *;
}<span style="font-size:18px;">
</span>


3、文件

在release模式下打包apk时会自动运行ProGuard,这里的release模式指的是通过ant release命令或eclipse project->android tools->export signed(unsigned) 
application package生成apk。
在debug模式下为了更快调试并不会调用proguard。
 
如果是ant命令打包apk,proguard信息文件会保存于<project_root>/bin/proguard文件夹内;
如果用eclipse export命令打包,会在<project_root>/proguard文件夹内。其中包含以下文件:

mapping.txt
表示混淆前后代码的对照表,这个文件非常重要。如果你的代码混淆后会产生bug的话,log提示中是混淆后的代码,希望定位到源代码的话就可以根据mapping.txt反推。
每次发布都要保留它方便该版本出现问题时调出日志进行排查,它可以根据版本号或是发布时间命名来保存或是放进代码版本控制中。


dump.txt
描述apk内所有class文件的内部结构。

seeds.txt
列出了没有被混淆的类和成员。

usage.txt
列出了源代码中被删除在apk中不存在的代码。

4、不能混淆的代码

顾名思义,不能混淆代码,否则会出错。

1、android系统组件,系统组件有固定的方法被系统调用。
2、被Android Resource 文件引用到的。名字已经固定,也不能混淆,比如自定义的View 。
3、Android Parcelable ,需要使用android 序列化的。
4、Java序列化方法,系统序列化需要固定的方法。
5、枚举 ,系统需要处理枚举的固定方法。
6、native方法,不能修改本地方法名
7、annotations 注释
8、其他Anroid 官方建议 不混淆的,如
android.app.backup.BackupAgentHelper
android.preference.Preference
com.android.vending.licensing.ILicensingService
9、反射的代码
10、系统或者自己的接口
11、数据库驱动
12、......

5、常见错误

1、Proguard returned with error code 1. See console
①、android-support-v4 不进行混淆

②、更新proguard版本  

③、添加缺少相应的库

④、后来发现是因为将整个工程放到了桌面上,而桌面的目录是C:/Documents and Settings/Administrator/桌面,在这里面有空格,而proguard进行发编译的时候是不允许有空格的,如果换了正确路径还不好用的话,直接删除proguard就好了

注意:SDK和程序路径最好不要有空格符
⑤、解决办法:将proguard.cfg中的"-dontpreverify"改成“-dontoptimize”,我把项目中生成的proguard文件夹(此时文件夹是空的)删掉,然后再重新运行项目,就OK

2、使用gson包解析数据时,出现missing type parameter异常
①在 proguard.cfg中添加

-dontobfuscate
-dontoptimize
②在 proguard.cfg中添加
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
3、类型转换错误
-keepattributes Signature
4、空指针异常
混淆过滤掉相关类与方法
5、安卓代码混淆与反射冲突,地图无法显示等问题解决及反编译方法,安卓反编译
     此前的代码混淆,因为并没有用到反射,所以常规的代码混淆方式一遍就能通过,而此项目中某些类利用到了反射机制(本人的这个项目中有即时通讯功能,所以有表情类资源,因此需要通过反射由文件名找到表情资源id),当由文件名去寻找资源id时就报空指针异常了,期初我并不知道什么原因,通过反编译已经混淆的apk,一步一步寻找到出错的地方,才恍然大悟,正是反射那一步出现了问题:Field field = R.drawable.class.getDeclaredField(name);走到这一步就挂了,程序直接崩溃。
解决办法:
   1.在proguard.cfg文件中,将反射用到的类中的变量不被混淆:
   如:-keep public class com.byl.bean.Expressions { *; },表示Expressions 这个类及类中的所有变量及方法不被混淆,注意要写全路径;
   2.过滤泛型:-keepattributes Signature
   3.最重要的一点: 保持R文件不被混淆,否则,你的反射是获取不到资源id的:-keep class **.R$* {*;}
6、android.provider.Settings$Global
# Project target.
target=android-19
7、java.lang.reflect.UndeclaredThrowableException
-keep interface com.dev.impl.**
8、内存溢出和无法写入堆栈
javaOptions in proguard := Seq(...)or
javaOptions in (Proguard, proguard) := Seq(...)
9、Error: Unable to access jarfile ..\lib\proguard.jar
路径问题
10、java.lang.NoSuchMethodError
没有相关方法,方法被混淆了,混淆过滤掉相关方法便可。
11、专业网站bug解决方法
http://proguard.sourceforge.net/index.html#manual/troubleshooting.html

总结

proguard的Android使用大概就是这些,够日常使用了。

这篇关于Android 编程下的代码混淆proguard的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/741103

相关文章

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

JAVA实现Token自动续期机制的示例代码

《JAVA实现Token自动续期机制的示例代码》本文主要介绍了JAVA实现Token自动续期机制的示例代码,通过动态调整会话生命周期平衡安全性与用户体验,解决固定有效期Token带来的风险与不便,感兴... 目录1. 固定有效期Token的内在局限性2. 自动续期机制:兼顾安全与体验的解决方案3. 总结PS

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Python屏幕抓取和录制的详细代码示例

《Python屏幕抓取和录制的详细代码示例》随着现代计算机性能的提高和网络速度的加快,越来越多的用户需要对他们的屏幕进行录制,:本文主要介绍Python屏幕抓取和录制的相关资料,需要的朋友可以参考... 目录一、常用 python 屏幕抓取库二、pyautogui 截屏示例三、mss 高性能截图四、Pill

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave