Android中的Proguard介绍

介绍

ProGuard是一个Java Class文件的Shrinker,optimizer,obfuscator以及Preverifier。

  • Shrinking步骤:检测,并且删除无用的classes,fields,methods,以及attributes
  • Optimization步骤:分析,并且优化bytecode中的methods
  • Obfuscation步骤:将剩下的classes,field,methods使用无意义的短的字符串重命名

这些步骤主要是为了让代码变得更精简,更高效,变得对逆向更难。而最后一个步骤:preverification,该步骤会在classes中添加预验证信息,而预验证的信息是在Java 6以上的版本所需要的。

这几个步骤每一个都是可选的,例如,ProGuard可以用来列出Dead Code,也可以在Java6中更高效的预验证class文件。

ProGuard

ProGuard只读取jars,wars,zips,ears等文件格式的文件。然后对它们进行shrinks,optimizes,obfuscates,preverifies。也可以传入多个文件,它们会一个一个被Shrink。ProGuard会把处理的结果写到一个或者多个Jar包中。如果输入的文件包含了资源文件,那么它们的名字和内容都会被obfuscated类名所影响。

ProGuard会指定Library Jar作为输入,而这些输入文件也是我们需要编译代码所需要的。ProGaurd使用它们来重建正确处理所需的类依赖关系,Library它们本身会保持不变,你可以把他们放到最终应用的Class Path中。

入口(Entry Points)

为了决定哪些代码应该被保留,而哪些代码应该被丢弃或者混淆的,你可以指定一个或者多个代码入口。这些入口可以是有main函数的class文件等等。

  • Shrinking:ProGuard会从这些入口出发,并且递归决定哪些classes以及class members会需要用到。而其他的classes和class members就会被丢弃
  • Optimization:ProGuard进一步优化代码。经过之前的优化,非入口的Classes和Methods都可以变成privatestaticfinal,而没用的参数也会被移除,一些函数会被内联
  • Obfuscation:ProGuard会重命名非入口的Class和Class Members。在整个过程中,会保持入口函数原有的名字来保证这些函数仍然可以呗访问
  • Preverification:这一步是唯一一步不需要知道入口的

反射(Reflection)

反射和自检(introspection)是代码自动处理中特殊的问题。

在ProGuard中,Classes和Class Member都可以创建或者通过名字动态调用,这种方式也是一个特殊的入口。

例如,Class.forName()可能会在Runtime引用很多的Class。而这种方式的类,我们无法预见哪些类必须使用原始名称来保留,例如Class的名称是从配置文件中读取的。

因此,我们需要在ProGuard的配置文件中进行配置。而最简单的配置则是通过-keep选项。然而,ProGuard已经检测并且处理了以下这些Case:

  • Class.forName("SomeClass")
  • SomeClass.class
  • SomeClass.class.getField("someField")
  • SomeClass.class.getDeclaredField("someField")
  • SomeClass.class.getMethod("someMethod", new Class[] {})
  • SomeClass.class.getMethod("someMethod", new Class[] { A.class })
  • SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[]{})
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] {A.class, B.class })
  • AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
  • AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
  • AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")

被引用的Class和Class Member会在Shrinking阶段被保存,并且String参数也会在Obfuscating阶段正确的更新

更多的,ProGuard对于Keep一些必须出现的Class或者Class Members有一些建议: 例如,ProGuard会关注到(SomeClass)Class.forName(variable).newInstance()。这种我们需要指定类或者SomeClass接口、实现类应该被保留。

混淆很多反射的代码需要反复测试,尤其是不需要内部构建的代码。

使用(Usages)

如果想要执行ProGuard,只需:

java -jar proguard.jar options ...

你可以在ProGuard安装的lib目录下找到proguard的Jar包。或者,把bin目录包含到命令行脚本中去。

一般我们都会把大多数的Options添加到一个配置文件中,如myconfig.pro,然后调用:

java -jar proguard.jar @myconfig.pro

你也可以在命令行参数后再添加其他的参数,例如:

java -jar proguard.jar @myconfig.pro -verbose

在配置文件中,我们可以通过##字符来进行注释。例如: ##This is Comment##

如果特殊的文件名带有空格,则需要使用单引号或者双引号。

Options可以通过命令行参数以及配置文件中任意组合。也就意味着,你可以引用任意的命令行参数,来避免Shell被特殊的字符扩张。

Options的顺序是无关的。

参考资料

Proguard官方文档

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术博文

让Json更懂中文(JSON_UNESCAPED_UNICODE)

我们知道, 用PHP的json_encode来处理中文的时候, 中文都会被编码, 变成不可读的, 类似”\u***”的格式, 还会在一定程度上增加传输的数据量....

3055
来自专栏Java3y

ConcurrentHashMap基于JDK1.8源码剖析

2668
来自专栏散尽浮华

Linux下针对服务器网卡流量和磁盘的监控脚本

2034
来自专栏Elasticsearch实验室

Elasitcsearch 底层系列 Lucene 内核解析之 Doc Value

       Elasticsearch 支持行存和列存,行存用于以文档为单位顺序存储多个文档的原始内容,在 Elasitcsearch 底层系列 Lucene...

3745
来自专栏大数据架构

Java进阶(四)线程间通信剖析

Java多线程编程中经常会碰到这样一种场景——某个线程需要等待一个或多个线程操作结束(或达到某种状态)才开始执行。比如开发一个并发测试工具时,主线程需要等到所有...

44016
来自专栏大内老A

ASP.NET MVC Controller激活系统详解:总体设计

我们将整个ASP.NET MVC框架划分为若干个子系统,那么针对请求上下文激活目标Controller对象的子系统被我们成为Controller激活系统。在正式...

2196
来自专栏大闲人柴毛毛

Java并发容器大合集

概述         java.util包中的大部分容器都是非线程安全的,若要在多线程中使用容器,你可以使用Collections提供的包装函数:synchro...

4026
来自专栏MasiMaro 的技术博文

Windows平台下的内存泄漏检测

在C/C++中内存泄漏是一个不可避免的问题,很多新手甚至有许多老手也会犯这样的错误,下面说明一下在windows平台下如何检测内存泄漏。 在windows平...

2232
来自专栏蘑菇先生的技术笔记

AutoMapper使用手册(一)

2414
来自专栏张善友的专栏

使用 Roslyn 编译器服务

.NET Core和 .NET 4.6中 的C# 6/7 中的编译器Roslyn 一个重要的特性就是"Compiler as a Service",简单的讲,就...

2018

扫码关注云+社区

领取腾讯云代金券