android 混淆那些事儿 -欧洲杯足彩官网

0顶
0踩

android 混淆那些事儿

2017-06-29 14:56 by 副主编 jihong10102006 评论(0) 有16427人浏览
本文主要讲述了代码混淆和资源混淆的原理,studio默认的混淆方案,混淆的参数,以及如何对apk进行代码混淆(自定义混淆文件)和资源混淆(结合微信混淆和美团混淆两种方案),避免apk被逆向。

为什么要混淆

我们的apk在打包发布之前,都要进行混淆处理来避免源代码和资源文件被小白用户通过反编译拿到。未混淆代码的反编译操作非常简单,网上有很多教程, 也可以通过使用android studio自带的apk分析工具(build—analyze apk)直接看到未混淆apk的源代码和原始的资源文件。对比图如下,从图中可以看到未混淆apk所有的代码都一目了然,随便改改资源和代码,就能变成一个新的apk。为了避免我们的劳动成果被窃取,也避免出现安全漏洞和隐患,此篇文章从混淆的原理到代码和资源文件的混淆实践做一下阐述。

混淆前:

混淆后:

混淆的原理

java 是一种跨平台、解释型语言,java 源代码编译成的class文件中有大量包含语义的变量名、方法名的信息,很容易被反编译为java 源代码。为了防止这种现象,我们可以对java字节码进行混淆。混淆不仅能将代码中的类名、字段、方法名变为无意义的名称,保护代码,也由于移除无用的类、方法,并使用简短名称对类、字段、方法进行重命名缩小了程序的size。

proguard由shrink、optimize、obfuscate和preverify四个步骤组成,每个步骤都是可选的,需要哪些步骤都可以在脚本中配置。 参见proguard。
  • 压缩(shrink): 侦测并移除代码中无用的类、字段、方法、和特性(attribute)。
  • 优化(optimize): 分析和优化字节码。
  • 混淆(obfuscate): 使用a、b、c、d这样简短而无意义的名称,对类、字段和方法进行重命名。
上面三个步骤使代码size更小,更高效,也更难被逆向工程。
  • 预检(preveirfy): 在java平台上对处理后的代码进行预检。
混淆流程图如下:

proguard读入input jars(or wars,zips or directories),经过四个步骤生成处理之后的jars(or wars,ears,zips or directories),optimization步骤可选择多次进行。

为了确定哪些代码应该被保留,哪些代码应该被移除或混淆,需要确定一个或多个entry point。entry point经常是带有main methods,applets,midlets的classes,它们在混淆过程中会被保留。我们来看一下proguard的几个步骤如何处理entry points。
  • 在压缩阶段,proguard从上述entry points开始遍历搜索哪些类和类成员被使用。其他没有被使用的类和类成员会移除。
  • 在优化阶段,proguard进一步设置非entry point的类和方法为private、static和final来进行优化,不使用的参数会被移除,某些方法会被标记被内联。
  • 在混淆阶段,proguard重命名非entry points的类和类成员。
  • 预检阶段是唯一没有触及entry points的阶段。
android studio 默认的混淆方案及字段解读

开启混淆

参见google官方文档 。

要通过proguard启动代码压缩,在build.gradle文件内相应的构建类型中添加minifyenabled true。
android {
    buildtypes {
        release {
            minifyenabled true
            proguardfiles getdefaultproguardfile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
    ...
}

除了 minifyenabled 属性外,还有用于定义 proguard 规则的 proguardfiles 属性:
proguardfiles getdefaultproguardfile('proguard-android.txt'),
                    'proguard-rules.pro'

google的官方文档介绍:

getdefaultproguardfile(‘proguard-android.txt’) 方法可从 android sdk tools/proguard/ 文件夹获取默认的 proguard 设置。要想做进一步的代码压缩,请尝试使用位于同一位置的 proguard-android-optimize.txt 文件。它包括相同的 proguard 规则,但还包括其他在字节码一级(方法内和方法间)执行分析的优化,以进一步减小 apk 大小和帮助提高其运行速度。

proguard-rules.pro 文件用于添加自定义 proguard 规则。默认情况下,该文件位于模块根目录(build.gradle 文件旁),内容为空。

通过试验,gradle 2.2之后,defaultproguardfile没有使用sdk目录下的proguard-android.txt,而是使用了gradle自带的proguard-android.txt,不同的gradle版本带有不同的默认混淆文件,在项目根目录的build/intermediates/proguard-files/proguard-android.txt-2.3.3(笔者用的gradle版本)即为gradle自带的混淆文件。在proguard-android.txt-2.3.3文件中也写有说明,gradle 2.2之后自带混淆文件:
引用
starting with version 2.2 of the android plugin for gradle, this file is distributed together with
the plugin and unpacked at build-time. the files in $android_home are no longer maintained and
will be ignored by new version of the android plugin for gradle.

构建输出

构建时proguard都会输出下列文件:

(1)dump.txt — 说明apk中所有类文件的内部结构
(2)mapping.txt — 提供原始与混淆过的类、方法和字段名称之间的转换
(3)seeds.txt — 列出未进行混淆的类和成员
(4)usage.txt — 列出从apk移除的代码

这些文件保存在/build/outputs/mapping/release目录下。

解码混淆过的堆叠追踪

使用混淆后,一定要保存好mapping文件,程序csh时通过脚本进行解码。
retrace工具位于/tools/proguard/目录中,解码命令为:
retrace.bat|retrace.sh [-verbose] mapping.txt [] 

例如mac平台下:
retrace.sh -verbose mapping.txt obfuscated_trace.txt

默认的混淆方案及字段解读

下面结合默认混淆文件中的内容来解释混淆的参数: 参见proguard
不使用大小写混写类名
-dontusemixedcaseclassnames

默认情况下混淆的类名可以包含大小写字符的混合。
不忽略公共类库
-dontskipnonpubliclibraryclasses

指定不去忽略非public的library classes。从proguard 4.5开始,是默认的设置。
-dontoptimize
-dontpreverify

默认optimize和preverify选项是关闭的,因为android的dex并不像java虚拟机需要optimize(优化)和previrify(预检)两个步骤。
指定哪个属性不要混淆,可一次指定多个属性
-keepattributes [attribute_filter]

通常exceptions, signature, deprecated, sourcefile, sourcedir, linenumbertable, localvariabletable, localvariabletypetable, synthetic, enclosingmethod, runtimevisibleannotations, runtimeinvisibleannotations, runtimevisibleparameterannotations, runtimeinvisibleparameterannotations, and annotationdefault属性需要被保留,根据项目具体使用情况保留。

这里需要特别注意的一点是,gradle默认的keepattributes属性不全,只保留了annotation,signature,innerclasses,enclosingmethod,为了混淆之后定位csh代码方便,我们需要在proguard_rules.pro中手动添加抛出异常时保留代码行号,并且重命名抛出异常时的文件名称,这样能方便定位问题:
抛出异常时保留代码行号
-keepattributes sourcefile,linenumbertable
重命名抛出异常时的文件名称
-renamesourcefileattribute sourcefile

keep选项非常重要,keep指定了哪些类,哪些方法不被混淆,从而保证了程序的正常运行。官方的keep用法有6种:

左边不带names的选项为from being removed or renames,即不会被移除或重命名,即使类或类成员未被使用。带有names的选项为from being renamed,不会被重命名,如果是无用的类或类成员,会被移除。

(1)-keep(names)选项 指定类和类成员(变量和方法)不被混淆
-keep [,modifier,...] class_specification

eg.
指定类名不被改变
-keep public class com.google.vending.licensing.ilicensingservice
指定使用了keep注解的类和类成员都不被改变
-keep @android.support.annotation.keep class * {*;}

关于keep注解的解释参见文末参考链接

(2)-keepclassmembers(names) 指定类成员不被混淆,类名会被混淆
-keepclassmembers [,modifier,...] class_specification

eg.keep setters in views 使得animations仍然能够工作
-keepclassmembers public class * extends android.view.view {
    void set*(***);
    *** get*();
}

(3)-keepclasseswithmembers(names) 指定类和类成员都不被混淆
-keepclasseswithmembers [,modifier,...] class_specification

eg.包含native方法的类名和native方法都不能被混淆,如果native方法未被调用,则被移除。由于native方法与对应so库中的方法名称对应,方法名被混淆会导致调用出现问题,所以native方法不能被混淆。
-keepclasseswithmembernames class * {
    native ;
}

通用options:
(1)-verbose 打印混淆详细信息

(2)-dontnote选项:指定不去输出打印该类产生的错误或遗漏
-dontnote com.android.vending.licensing.ilicensingservice
-dontnote android.support.**

(3)-dontwarn选项:指定不去warn unresolved references和其他重要的problem
-dontwarn android.support.**

如上面(2)(3)所示,android.support的libraries需要保留

至此,gradle自带的proguard-android.txt文件相关字段已解析完毕。下面将介绍我们自定义的proguard-rules.pro文件需要添加什么参数。

自定义混淆文件

一般而言,我们会定义我们自己的proguard-rules.pro,下面列出自定义的一个proguard-rules.pro供大家参考。在看自定义的混淆文件之前,先讲解一下filters和assumenosideeffects,以便更好地理解下面的指令。

(1)filters
?   matches any single character in a name.(匹配一个字符)
*   matches any part of a name not containing the directory separator.(匹配一个名字,除了目录分隔符外的任意部分)
**  matches any part of a name, possibly containing any number of directory separators.(匹配任意名,可能包含任意路径分隔符)
!  exclude
     匹配类中的所有字段
    匹配类中所有的方法
      匹配类中所有的构造函数

eg.
-keep class com.lily.test.** 本包和所包含子包下的类名都保持
-keep class com.lily.test.* 保持该包下的类名
-keep class com.lily.test.** {*;} 保持包和子包的类名和里面的内容均不被混淆

(2)-assumenosideeffects 指令: 下文会用在android log的移除上
assumeosideeffects是optimization过程中的选项,所以为保证指令的有效,需要开启optimization。这个指令的含义是proguard会在optimization过程中删除对这些方法的调用,需要注意:only use this option if you know what you’re doing!

下面是自定义混淆文件的一个范例,四大组件,native方法,反射用到的类,一些引入的第三方库等都不能进行混淆:
# 代码混淆压缩比,在0~7之间
-optimizationpasses 5
# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames
# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
# 不做预校验,preverify是proguard的四个步骤之一,android不需要preverify,去掉这一步能够加快混淆速度。
-dontpreverify
-verbose
#google推荐算法
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
# 避免混淆annotation、内部类、泛型、匿名类
-keepattributes *annotation*,innerclasses,signature,enclosingmethod
# 重命名抛出异常时的文件名称
-renamesourcefileattribute sourcefile
# 抛出异常时保留代码行号
-keepattributes sourcefile,linenumbertable
# 处理support包
-dontnote android.support.**
-dontwarn android.support.**
# 保留四大组件,自定义的application等这些类不被混淆
-keep public class * extends android.app.activity
-keep public class * extends android.app.appliction
-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.preference.preference
-keep public class com.android.vending.licensing.ilicensingservice
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
    native ;
}
# 保留枚举类不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueof(java.lang.string);
}
# 保留parcelable序列化类不被混淆
-keep class * implements android.os.parcelable {
    public static final android.os.parcelable$creator *;
}
#第三方jar包不被混淆
-keep class com.github.test.** {*;}
#保留自定义的test类和类成员不被混淆
-keep class com.lily.test {*;}
#保留自定义的xlog文件夹下面的类、类成员和方法不被混淆
-keep class com.test.xlog.** {
    ;
    ;
}
#assume no side effects:删除android.util.log输出的日志
-assumenosideeffects class android.util.log {
    public static *** v(...);
    public static *** d(...);
    public static *** i(...);
    public static *** w(...);
    public static *** e(...);
}
#保留keep注解的类名和方法
-keep,allowobfuscation @interface android.support.annotation.keep
-keep @android.support.annotation.keep class *
-keepclassmembers class * {
    @android.support.annotation.keep *;
}

资源文件的混淆:

上面讲述了如何进行代码混淆,再来讲讲如何对资源文件进行混淆。对资源文件进行混淆操作本质上是通过修改resources.arsc(参见文末链接详见resources.arsc作用及文件格式)。现针对两种资源混淆方案进行简要说明。第一种是,第二种是,两篇文章中都对原理进行了详细的阐述。
(1)微信的资源混淆方案:
微信的资源混淆是自己做了一个安装包解压并且用7z极限压缩打包器,修改的内容也是resources.arsc,优点是可以最大地混淆,不依赖源码与编译过程,无需在编译过程中修改源文件(java、xml、资源文件),无需改变android打包流程。整体的流程如下:

使用微信的资源混淆方案有两种方法,第一种方式为,第二种方式为直接。下图为使用命令行最简单的方法生成资源混淆的apk,下载后,进入tool_output文件夹,试验的apk为test.apk
java -jar andresguard-cli-1.2.3.jar test.apk

混淆过程中会输出log,混淆后会出现和apk同名的文件夹,里面包含了混淆后mapping的对应文件,新签名打包的apk和混淆后的资源文件目录。如下图所示:

混淆前资源文件:

混淆后资源文件:

可以看到资源文件的路径以及文件名都被混淆了。
(2)美团的资源混淆方案:
采用更改aapt(android asset packaging tool)(参见文末链接详细解读aapt)源码的方式,参考了proguard obfuscator,对apk中资源文件名使用简短无意义名称进行替换,如下面代码所示,在aapt生成resources.arsc和*.ap*时把资源文件的名称进行替换。下面是美团修改后的resource.cpp文件
static status_t makefileresources(bundle* bundle, const sp& assets,
                                      resourcetable* table,
                                      const sp& set,
                                      const char* restype)
    {
        string8 type8(restype);
        string16 type16(restype);
        bool haserrors = false;
        resourcediriterator it(set, string8(restype));
        ssize_t res;
        while ((res=it.next()) == no_error) {
            if (bundle->getverbose()) {
                printf("    (new resource id %s from %s)\n",
                       it.getbasename().string(), it.getfile()->getprintablesource().string());
            }
            string16 basename(it.getbasename());
            const char16_t* str = basename.string();
            const char16_t* const end = str   basename.size();
            while (str < end) {
                if (!((*str >= 'a' && *str <= 'z')
                        || (*str >= '0' && *str <= '9')
                        || *str == '_' || *str == '.')) {
                    fprintf(stderr, "%s: invalid file name: must contain only [a-z0-9_.]\n",
                            it.getpath().string());
                    haserrors = true;
                }
                str  ;
            }
            string8 respath = it.getpath();
            respath.converttorespath();
            string8 obfuscationname;
            string8 obfuscationpath = getobfuscationname(respath, obfuscationname);
            table->addentry(sourcepos(it.getpath(), 0), string16(assets->getpackage()),
                            type16,
                            basename, // string16(obfuscationname),
                            string16(obfuscationpath), // respath
                            null,
                            &it.getparams());
            assets->addresource(it.getleafname(), obfuscationpath/*respath*/, it.getfile(), type8);
        }
        return haserrors ? unknown_error : no_error;
    }

修改的部分在:
string8 obfuscationname;
string8 obfuscationpath = getobfuscationname(respath, obfuscationname);
assets->addresource(it.getleafname(), obfuscationpath/*respath*/, it.getfile(), type8);

混淆时常见的问题解决

参见

参考文献:
1、
2、
3、
4、
5、[http://www.jianshu.com/p/60ce4bf20f72url=""]android resources.arsc文件格式及逆向修改res路径思路[/url]
6、
  • 大小: 43.5 kb
  • 大小: 84.8 kb
  • 大小: 39 kb
  • 大小: 7.5 kb
  • 大小: 70.3 kb
  • 大小: 85.7 kb
  • 大小: 98.6 kb
  • 大小: 31.3 kb
来自:
0
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 讲述数学起源,古埃及数学、古巴比伦数学,中国数学发展史以及古希腊数学。

  • 本文提出了一种新的高效算法,用于使用二项式树计算希腊人的期权。 我们还显示,本文介绍的用于欧洲期权的希腊人渐近等效于malliavin希腊人的离散版本。 这一事实使我们能够证明,在连续时间模型中,我们的希腊人收敛到了malliavin希腊人。 本文还给出了使用二项式树的希腊人针对美式期权的计算算法。 使用二项式树法进行希腊语计算有三个优势。 首先,数学比使用连续时间malliavin微积分方法简单得多。 其次,我们可以构造一个简单的算法来获取美式期权的希腊文。 第三,这种算法非常有效,因为它可以一次计算价格和希腊字母(delta,gamma,vega和rho)。 尽管它很重要,但由于对最优止损问题进行敏感性分析很困难,因此以前只有很少的研究针对美式期权计算希腊语。 我们相信,我们的方法将成为计算希腊期权价格的一种流行方法。

  • 在这项研究中,提出了从财务报表分析中获得的自举数据分析,以评估希腊主权债务危机爆发后希腊上市公司并购的短期经营收益。 在希腊债务危机的五年内,被调查的样本包括30家希腊公司,以调查合并带来的经营收益程度。 结果表明,在并购事件发生的前一年和后一年,样本公司无法以几种财务比率产生短期经营收益。 另外,我们得出结论,应谨慎使用基于标准,基于正态性的t检验来推断财务比率。

  • 在西方文明的两大发源地——希腊和希伯来——分别诞生了哲学和犹太教,基督教实为两大古代文明汇合而生的异果。就柏拉图与摩西的关系,作为基督教护教者,早期教父展现了由不同的立场所构成的光谱:从最初简单拒斥柏拉图,到控诉柏拉图剽窃摩西,到最终礼赞柏拉图为"希腊的摩西",并授予他仅次于摩西及其他先知的二号角色。在此过程中,通过由柏拉图哲学所代表的希腊哲学,基督教突破犹太教的民族性,而走向了"普世化的一神教"。

  • 老师对学生行为举止的问卷调查(tesc)评估老师认为学生的举止。 不存在先验结构模型的假设。 因此,本研究试图首先使用探索性因子分析,然后再使用确认性因子分析来确定希腊tesc因子结构的潜在关系。 71名教师对1201名学生进行了评估。 将样本分为两部分,以在不同的子样本中执行efa和cfa。 全民教育采用kaiser> 1规则,velicer的最小平均部分检验和horn的平行分析,形成了一个两因素结构。 该欧洲杯足彩官网的解决方案证实了罗纳(rohner)提出的理论分类。 cfa支持在efa中开发的二维结构,其两因素模型显示出最佳拟合。 共同潜在因子(clf)表示没有方法偏差会改变cfa结果。 内部一致性可靠性足够。 tesc的析因分析的首次尝试是希腊文,它提供了内部一致性和结构效度的初步证据。

  • 介绍proguard基础语法和逆混淆工具的使用

  • android 开发中为了代码安全一般都会使用 proguard 进行代码...这是许多开发者对代码混淆的认识,但是 proguard 更深入的内容呢,如何配置混淆规则呢,下面我就分享下 android 中 proguard 那些事。先敲敲黑板,划下...

  • 所以在androidstudio中如果需要生成jar或者aar,就需要将module变成library。 1、androidstudio生成library 在这里介绍androidstudio两种生成library的方式。 1.1、两种生成library的方式 新建library module。 ...

  • android studio自身集成java语言的proguard作为压缩,优化、混淆和预检工具,配合gradle构建工具使用很简单,只需要在工程应用目录的gradle文件中设置minifyenabled为true即可。然后我们就可以到proguard-rules.pro...

  • 在 android 日常开发过程中,混淆是我们开发 app 的一项必不可少的技能。只要是我们亲身经历过 app 打包上线的过程,或多或少都需要了解一些代码混淆的基本操作。那么,混淆到底是什么?它的好处有哪些?具体效果...

  • 相信不少开发在发布时被代码混淆弄得一头雾水,大多都是百度一下,看看别人的混淆规则,复制粘贴拿来试一试,直到最后弄成了,也不知道为什么混淆规则要这么写,以及混淆都对自己的代码做了什么?不要问我为什么这么...

  • android 混淆详解 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/69388246 本文出自【赵彦军的博客】 混淆的基本概念 什么是混淆? 代码混淆亦称花指令,是将计算机程序的代码,转换成一种...

  • gradle插件-混淆器字符串加密(android / java) 这个项目是一个简单的gradle插件,可帮助您在编译时加密android java代码的所有string值。 重要提示:如果您的项目不受git或svn之类的scm工具管理,则enigma插件将...

  • android 引入了proguard,proguard 是android tools包中提供用来对代码进行压缩,优化和进行混淆的工具,它能够移除无用的代码,对类名,方法名,字段名进行重命名,但不改变代码的结构,从而达到对代码混淆的作用。...

  • 在 android 日常开发过程中,混淆是我们开发 app 的一项必不可少的技能。只要是我们亲身经历过 app 打包上线的过程,或多或少都需要了解一些代码混淆的基本操作。那么,混淆到底是什么?它的好处有哪些?具体效果...

  • android混淆打包那些事儿混淆简介说到混淆,就要说到proguard,android的混淆是有proguard来完成的,proguard是一个开源项目在sourceforge上进行维护。流程代码混淆是包含了代码压缩、优化、混淆等一系列行为的过程...

  • 1.our god is marching on! - 25 march 1965 在线收听 let us therefore continue our triumphant march (uh huh) to the realization of the american dream. (yes, sir) let us march on segregated housing (yes, si

  • 上一次贴了马丁路德金博士的三段演讲, 今天再贴一些,另外大家可以去http://www.stanford.edu/group/king/popular_requests/ 找到更多。 1. ive been to the mountaintop - 3 april 1968 (kings last speech)dr. martin luther king, jr. delivered

  • 刚才被这个故事感动得热泪盈眶: “请帮助另外10个人吧”———一个德国小孩的故事------------------------------------------   这是发生在德国的一个真实感人的故事。2003年母亲节,节日的温馨气氛再次燃起了伊特洛孤儿院孤儿德比对母亲的思念。电视机内一个6岁的小男孩在帮父母修剪草坪,德比对修

global site tag (gtag.js) - google analytics
网站地图