android混淆

2023-05-16

首先要说的话:

本文是对好几个博文的摘录再加上我自己的理解,以尊重原创为原则,下面贴出相关博文的链接

Android有效地减少方法数

http://blog.csdn.net/lihenair/article/details/51657099

Android 项目的代码混淆,Android proguard 使用说明

http://blog.csdn.net/catoop/article/details/47208833

Android安全攻防战,反编译与混淆技术完全解析(下)

http://blog.csdn.net/guolin_blog/article/details/50451259 

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

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

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

android默认的混淆配置文件,我们来一起逐行阅读一下。 
-dontusemixedcaseclassnames 表示混淆时不使用大小写混合类名。 
-dontskipnonpubliclibraryclasses 表示不跳过library中的非public的类。 
-verbose 表示打印混淆的详细信息。 
-dontoptimize 表示不进行优化,建议使用此选项,因为根据proguard-android-optimize.txt中的描述,优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行。 
-dontpreverify 表示不进行预校验。这个预校验是作用在Java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。 
-keepattributes *Annotation* 表示对注解中的参数进行保留。

-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

表示不混淆上述声明的两个类,这两个类我们基本也用不上,是接入Google原生的一些服务时使用的。

-keepclasseswithmembernames class * {
    native <methods>;
}

表示不混淆任何包含native方法的类的类名以及native方法名,这个和我们刚才验证的结果是一致的。

-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

表示不混淆任何一个View中的setXxx()和getXxx()方法,因为属性动画需要有相应的setter和getter的方法实现,混淆了就无法工作了。

-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

表示不混淆Activity中参数是View的方法,因为有这样一种用法,在XML中配置android:onClick=”buttonClick”属性,当用户点击该按钮时就会调用Activity中的buttonClick(View view)方法,如果这个方法被混淆的话就找不到了。

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

表示不混淆枚举中的values()和valueOf()方法,枚举我用的非常少,这个就不评论了。

-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

表示不混淆Parcelable实现类中的CREATOR字段,毫无疑问,CREATOR字段是绝对不能改变的,包括大小写都不能变,不然整个Parcelable工作机制都会失败。

-keepclassmembers class **.R$* {
    public static <fields>;
}

表示不混淆R文件中的所有静态字段,我们都知道R文件是通过字段来记录每个资源的id的,字段名要是被混淆了,id也就找不着了。 
-dontwarn android.support.** 表示对android.support包下的代码不警告,因为support包中有很多代码都是在高版本中使用的,如果我们的项目指定的版本比较低在打包时就会给予警告。不过support包中所有的代码都在版本兼容性上做足了判断,因此不用担心代码会出问题,所以直接忽略警告就可以了。 
好了,这就是proguard-android.txt文件中所有默认的配置,而我们混淆代码也是按照这些配置的规则来进行混淆的。经过我上面的讲解之后,相信大家对这些配置的内容基本都能理解了。不过proguard语法中还真有几处非常难理解的地方,我自己也是研究了好久才搞明白,下面和大家分享一下这些难懂的语法部分。 
proguard中一共有三组六个keep关键字,很多人搞不清楚它们的区别,这里我们通过一个表格来直观地看下:

关键字 描述
keep 保留类和类中的成员,防止它们被混淆或移除。
keepnames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
keepclassmembers 只保留类中的成员,防止它们被混淆或移除。
keepclassmembernames 只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
keepclasseswithmembers 保留类和类中的成员,防止它们被混淆或移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。
keepclasseswithmembernames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。

除此之外,proguard中的通配符也比较让人难懂,proguard-android.txt中就使用到了很多通配符,我们来看一下它们之间的区别:

通配符 描述
<field> 匹配类中的所有字段
<method> 匹配类中的所有方法
<init> 匹配类中的所有构造函数
* 匹配任意长度字符,但不含包名分隔符(.)。比如说我们的完整类名是com.example.test.MyActivity,使用com.*,或者com.exmaple.*都是无法匹配的,因为*无法匹配包名中的分隔符,正确的匹配方式是com.exmaple.*.*,或者com.exmaple.test.*,这些都是可以的。但如果你不写任何其它内容,只有一个*,那就表示匹配所有的东西。
** 匹配任意长度字符,并且包含包名分隔符(.)。比如proguard-android.txt中使用的-dontwarn android.support.**就可以匹配android.support包下的所有内容,包括任意长度的子包。
*** 匹配任意参数类型。比如void set*(***)就能匹配任意传入的参数类型,*** get*()就能匹配任意返回值的类型。
匹配任意长度的任意类型参数。比如void test(…)就能匹配任意void test(String a)或者是void test(int a, String b)这些方法。

虽说上面表格已经解释的很详细了,但是很多人对于keep和keepclasseswithmembers这两个关键字的区别还是搞不懂。确实,它们之间用法有点太像了,我做了很多次试验它们的结果都是相同的。其实唯一的区别就在于类中声明的成员存不存在,我们还是通过一个例子来直接地看一下,先看keepclasseswithmember关键字:

-keepclasseswithmember class * {
    native <methods>;
}

这段代码的意思其实很明显,就是保留所有含有native方法的类的类名和native方法名,而如果某个类中没有含有native方法,那就还是会被混淆。 
但是如果改成keep关键字,结果会完全不一样:

-keep class * {
    native <methods>;
}

使用keep关键字后,你会发现代码中所有类的类名都不会被混淆了,因为keep关键字看到class *就认为应该将所有类名进行保留,而不会关心该类中是否含有native方法。当然这样写只会保证类名不会被混淆,类中的成员还是会被混淆的。 

文件

通过eclipse project->android tools->export signed(unsigned) application package生成apk,会自动运行ProGuard。
在debug模式下为了更快调试并不会调用proguard。


如果是ant命令打包apk,proguard信息文件会保存于工程代码下的/bin/proguard文件夹内;
如果用eclipse export命令打包,也会在/proguard文件夹内。其中包含以下文件:


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


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

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

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


不能混淆的代码

顾名思义,不能混淆代码如果被混淆了,就会出现错误。

1、需要反射的代码

2、系统接口

3、Jni接口

4、需要序列号和反序列化的代码(即实现Serializable接口的JavaBean)

5、与服务端进行元数据交互的JavaBean(JSON、XML中对应的类)

……

常见错误

1) Proguard returned with error code 1. See console

  > 更新proguard版本
  > android-support-v4 不进行混淆
  > 添加缺少相应的库

2) 使用gson包解析数据时,出现 missing type parameter 异常

  > 在 proguard-project.txt 中添加
    -dontobfuscate
    -dontoptimize
  > 在 proguard-project.txt 中添加
    # 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) 类型转换错误

  > 在 proguard-project.txt 中添加
    -keepattributes Signature

4) 空指针异常

  > 混淆过滤掉相关类与方法

5) java.lang.reflect.UndeclaredThrowableException

  > -keep interface com.dev.impl.**

6) Error: Unable to access jarfile ..libproguard.jar

  > 路径问题

7) java.lang.NoSuchMethodError

  > 这也是最常见的问题,因为找不到相关方法,方法被混淆了,混淆过滤掉相关方法便可。


默认混淆规则的几点总结:

1.普通类肯定是会被混淆的,不管是类名、方法名还是变量名。没有被调用方法会被认为是多余的代码,在打包的时候就给移除掉。不仅仅是代码,没有被调用的资源同样也会被移除掉,因此混淆可以起到压缩APK包的作用。 

2.凡是需要在AndroidManifest.xml中去注册的所有类的类名以及从父类重写的方法名都自动不会被混淆。因此,除了Activity之外,这份规则同样也适用于Service、BroadcastReceiver和ContentProvider。 

3.只要一个类中有存在native方法,它的类名就不会被混淆,native方法的方法名也不会被混淆,因为C++代码要通过包名+类名+方法名来进行交互。 但是类中的别的代码还是会被混淆的。 如果native方法没被调用,则该方法被移除;如果类中所有方法都没被调用,那么该类相当于没本地方法,会被混淆。

4.当一个类只是被import,而没有在代码中调用,则这个类会被移除。

5.如果工程代码里的方法数过多,那么构建工程花的时间就长。而如果不被使用的方法也多的话,使用混淆能去掉这些代码,但不能减少构建时间,因为构建所要处理的代码并没有减少。所以在选择库文件或框架的时候尽量选择功能单一的,轻量级的。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android混淆 的相关文章

  • 房间数据库更改未触发观察者

    当房间数据库更改时 我试图更新 RecyclerView 但是 当数据库发生更改时 不会调用 MainActivity 中定义的观察者的 onChanged 方法 如果我让 DAO 返回 LiveData 而不是 List 并在 ViewM
  • 在根项目“bin”中找不到任务“bintrayUpload”

    我遵循了将 AAR 文件发布到 JCenter 所需的每个步骤 然后使用 Maven Central 将其同步https github com danielemaddaluno gradle jcenter publish https gi
  • Android 应用程序安装失败:包 com.my.app 在条目 AndroidManifest.xml 处没有证书

    在 Android Studio 中 我生成了带有密钥库等的签名 APK 将 APK 安装到设备上时失败 并显示 无法安装应用程序 并且在 Android Monitor 中我看到以下行 Package com my app has no
  • 如何从Firebase Firestore实时更新文档中获取修改后的字段或数据? [复制]

    这个问题在这里已经有答案了 我有多个文档 我的问题是我无法获取修改的特定数据 我正在获取完整的文档 db collection employees whereEqualTo OID OID addSnapshotListener new E
  • 吉夫伦致命信号11

    我正在尝试使用一些本机代码来创建 Gif 我使用绘画绘制图像 创建一些笔画 单击 保存 绘制的图像将保存为 JPG 格式 当我单击 创建 Gif 时 它会获取所有图像并开始创建 gif 这是当我收到致命信号 11 并且应用程序重新启动时 我
  • 为什么反射会减慢Android手机的速度

    我多次读到反射会降低手机性能 这有多真实 例如 在我的例子中 我从 Web 服务获取一些参数 这些参数与我在 Android 应用程序中的类的参数同名 所以我只是使用java字段和反射设置这些参数的值 它似乎并没有降低性能 有人可以向我解释
  • 当路径的点超出视野时,Android Canvas 不会绘制路径

    我在绘制路径时遇到了 Android Canvas 的一些问题 我的情况是 我有一个相对布局工作 如地图视图 不使用 google api 或类似的东西 我必须在该视图上绘制一条路径 canvas drawPath polyPath bor
  • Fragment 问题中的 ExpandableListView

    我正在尝试在片段中实现可扩展列表视图 没有错误出现 当我尝试记录两个的输出时List
  • 需要 Android webview window.open() 和 window.close() 的信息

    我正在开发一个安卓应用程序 这是我网站的 WebView 该网站包含一个弹出按钮 单击该按钮后 将打开一个新窗口并显示内容 该链接可以来自外部站点 然而 当我实现此操作时 新选项卡正在打开 之后它会弹出以打开浏览器 尽管在 Web 视图中打
  • 错误类型 3 - 活动类不存在

    我正在尝试运行 webRTC 应用程序 但返回以下错误 启动应用程序 com onlinevoicecallapp com onlinevoicecallapp MainActivity 设备外壳命令 am start n com onli
  • 透明 9patch 图像:显示出线条

    我得到了一个透明的 9 补丁图像 其中有 9 条补丁线显示槽 This is the output 显然我不希望水平线可见 这就是我创建 9patch 的方式 This is the final image that is used in
  • Android -room 持久库 - DAO 调用是异步的,因此如何获取回调?

    从我读到的Room 不允许您在主线程上发出数据库查询 因为可能会导致主线程延迟 所以想象一下我正在尝试更新 UI 主线程上的文本视图 其中一些数据我将如何得到回调 让我给你举个例子 想象一下 我想将我的业务模型数据存储到一个名为 事件 的对
  • 在新的 intel x86 android 模拟器中访问 google api

    我只是尝试在新的 x86 android 模拟器中运行我公司的应用程序 但是我们的应用程序依赖于 google 地图 API 而这在 google 随 android sdk 版本 17 提供的 x86 系统映像中不可用 我的直觉告诉我答案
  • Android 中的 OpenGL 缩小

    我正在使用 3D 对象并渲染它并通过扩展 GLSurfaceView 实现渲染器来显示它 问题是如何通过捏合和捏合进行缩小 下面是我的班级 package com example objLoader import java nio Byte
  • onTaskRemoved() 在华为和小米设备中没有被调用

    我一直在使用onTaskRemoved 服务中的方法 用于检测应用程序何时通过滑动从设备最近列表中删除 我执行一些日志记录和发生这种情况时需要执行的一些其他操作 它工作完美 然后我在运行Android 6 0的华为设备上检查了这个方法 该方
  • 离子初始加载时间

    我正在使用 Ionic 构建一个简单的应用程序 但我的应用程序在冷启动时的初始加载时间方面存在性能问题 这是我所做的 collection repeat 代替带有 track by 的 ng repeat 原生滚动 overflow scr
  • Android 标记如何实现拖放?

    你好 我正在 Android 中开发 MapView 应用程序 我有三个标记 我希望稍后能够使用 Google Map API getlocation function 为了尝试一下 我想使用拖放功能移动标记 然后检查位置 任何人都可以通过
  • 丢失应用程序的密钥库文件(但已启用 Google Play 应用程序签名)

    我已经失去了原来的keystore用于签署我的应用程序的文件 我的应用启用了 Google Play 应用签名 如果我联系 Google 支持人员 是否可以重置密钥 以便我可以继续上传到此包 我希望我可以做到这一点 因为应用程序签名已启用
  • Android MulticastSocket.joinGroup 不会触发发送 IGMP 消息

    Code MulticastSocket s new MulticastSocket InetAddress addr InetAddress getByName 230 230 230 1 s joinGroup addr 在 Ubunt
  • LifeCycleAware Fragment 中的片段生命周期事件

    我有一个生命周期感知片段和一个LifecycleObserver class public class MyFragment extends Fragment Override public void onCreate Nullable B

随机推荐

  • qt 编译qgc常见问题

    qt LINK warning LNK4098 默认库 MSVCRT 与其他库的使用冲突 xff1b 请使用 NODEFAU 如果以前没有问题 xff0c 突然出现的这个问题 xff0c 绝大可能是中间编译过程太多造成的 清理项目 重新构建
  • VINS-FUSION-GPU在jetson nx上的实现

    需要安装经过修改的Ubuntu18系统 https span class token operator span span class token comment developer nvidia com zh cn embedded do
  • 主机ping通虚拟机,虚拟机ping通主机解决方法(NAT模式)

    主机ping通虚拟机 xff0c 虚拟机ping通主机解决方法 xff08 NAT模式 xff09 有时候需要用虚拟机和宿主机模拟做数据交互 xff0c ping不通是件很烦人的事 xff0c 本文以net模式解决这一问题 宿主机系统 xf
  • 一个基于Matlab的简单Gui设计

    前几日浩子说要编一个基于Matlab的用户图像界面 xff0c 他用GUIDE搭了一个大概的框架 xff0c 大概要实现数据读入 做图分析 图像清除 关闭界面的功能 xff0c 我用函数形式给改编了一个 xff0c 虽然问题比较简单 xff
  • 关于N步相移中相位噪声仿真分析的一点说明

    在条纹投影的三维测量中 xff0c 有这么一个经典的结论 xff1a 假设光强的噪声为方差为 2 xff0c 那么 xff0c 经过N步标准相移求得的相位的方差为2 2 N B 2 xff08 xff09 xff0c 其中 xff0c B为
  • 如何给MFC对话框添加背景图片

    一 创建项目 文件 新建项目 MFC应用程序 该页面使用 基于对话框 完成即可 注意 取消 使用Unicode库 否则在使用AfxMessageBox会报错 xff0c 没有一个可以转换的参数类型 xff0c 要加AfxMessageBox
  • 如何检测应用程序调用了哪些DLL文件?

    之前所用的检测工具是Dllshow xff0c 后来突然不能用了 xff0c VS以前有Depends xff0c 后来高级版本也没了 最近找到一种简单方便的方法 xff0c 利用windowsx系统自带的功能 运行你想知道的应用程序 xf
  • 网络编程懒人入门(一):快速理解网络通信协议(上篇)

    1 写在前面 论坛和群里常会有技术同行打算自已开发IM或者消息推送系统 xff0c 很多时候连基本的网络编程理论 xff08 如网络协议等 xff09 都不了解 xff0c 就贸然定方案 写代码 xff0c 显得非常盲目且充满技术风险 即时
  • Matlab中调用C++dll

    利用mex技术可以实现这个功能 xff0c 但是必须例外写一个接口函数 xff0c 比较麻烦 利用dll调用的方法 xff0c 简单方便 下面就以实现加法函数add 为例 xff0c 来详细介绍具体过程 一 利用VS生成dll文件 利用VS
  • 大小端序与端序转换

    最近在做客户项目的时候 xff0c 遇到了不同厂家的安防相机输出的数据大小端序不一致的情况 xff0c 导致在使用同一种方式处理时 xff0c 出现了错误 虽然问题已经解决 xff0c 还是顺手把大小端序的知识简单梳理一下 1 大端序和小端
  • debian ware source

    deb http ftp cn debian org debian jessie main non free contrib deb http ftp cn debian org debian jessie proposed updates
  • debian中文输入法——拼音和五笔的解决方法

    最近安装Debian操作系统 xff0c 但遇到一个重大的困惑 xff0c 那就是为什么Debian菜单里面有一个Fcitx的选项 xff0c 但是为什么就是无法调出前端来实现输入 xff0c 这是个大问题 xff0c 于是就研究 xff0
  • YOLOv5图像分割中的NMS处理

    在上一篇文章YOLOv5图像分割 SegmentationModel类代码详解有讲到图像经过YOLOv5网络后得到的输出形式 xff0c 主要是调用了BaseModel类下的forward得到的输出 xff0c 输出的shape为 batc
  • YOLO之trt推理+Diou/iou目标跟踪以及计数【附代码】

    本篇文章是对之前YOLOv4 tensorrt推理项目的更新 xff0c 在trt推理 xff0c 多进程语音报警的功能中又新添加了目标跟踪 可用于目标计数 采用IOU进行跟踪 也可以选用DIOU yolov4 43 deepsort可以参
  • yolov5_reid【附代码,行人重识别,可做跨视频人员检测】

    该项目利用yolov5 43 reid实现的行人重识别功能 xff0c 可做跨视频人员检测 应用场景 xff1a 可根据行人的穿着 体貌等特征在视频中进行检索 xff0c 可以把这个人在各个不同摄像头出现时检测出来 可应用于犯罪嫌疑人检索
  • src目录和项目路径的联系

    code src目录里面的东西会被eclipse编译 xff0c 编译完了就放到了 bin目录下 xff0c 而bin目录就是我们项目的classPath code
  • 逆向加固分析

    34 libsecexe so 34 34 梆梆加固免费版 34 34 libsecmain so 34 34 梆梆加固免费版 34 34 libSecShell so 34 34 梆梆加固免费版 34 34 secData0 jar 34
  • android之visibility的三个属性

    android visibility 61 34 34 其有三个属性 xff1a visible显示 xff1b invisible显示黑背景条 xff0c 在这种情况下它会占据空间 xff1b gone不显示 在类中 xff0c 可以设置
  • android中的Application类

    在2011年做的一个iptv项目中就接触了这个Application类 xff0c 虽用起来简单 xff0c 但还是有些需要注意的地方 空闲之余 xff0c 总结如下 xff1a android 系统为每个程序运行时创建一个Applicat
  • android混淆

    首先要说的话 xff1a 本文是对好几个博文的摘录再加上我自己的理解 xff0c 以尊重原创为原则 xff0c 下面贴出相关博文的链接 Android有效地减少方法数 http blog csdn net lihenair article