当前位置:   article > 正文

混淆技术研究笔记(二)yGuard入门

yguard

logo
yGuard官方文档地址:https://yworks.github.io/yGuard/index.html

yGuard官方文档包含了比较全面的内容,由于文档是英文的,而且文档翻译后的浏览效果不是特别好,所以看文档入门有点难度。

这个系列的重点是混淆,所以不会涉及yGuard中的shrink用法,主要是rename的用法。

本文使用的 maven-antrun-plugin 插件,插件的基本配置如下:

<plugin>
  <artifactId>maven-antrun-plugin</artifactId>
  <version>1.8</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <id>obfuscate</id>
      <configuration>
        <tasks>
          <!-- Ant具体配置 -->
        </tasks>
      </configuration>
    </execution>
  </executions>
</plugin>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在插件配置的 <tasks> 中是 Ant 的具体配置,下面是一个参考官方示例修改过的配置,针对单个模块的配置。

<tasks>
  <property
   name="project.jar"
   value="${project.build.directory}/${project.build.finalName}.jar"/>
  <property
   name="project.jar.unobf"
   value="${project.build.directory}/${project.build.finalName}_unobf.jar"/>
  <move
   file="${project.jar}"
   tofile="${project.jar.unobf}"
   verbose="true"/>

  <property
   name="runtime_classpath"
   refid="maven.runtime.classpath"/>
  <taskdef
   name="yguard"
   classname="com.yworks.yguard.YGuardTask"
   classpath="${runtime_classpath}"/>
  <yguard>
    <inoutpair in="${project.jar.unobf}" out="${project.jar}" />

    <externalclasses>
      <pathelement location="${runtime_classpath}"/>
      <!-- 下面配置是错误的 -->
      <pathelement location="${maven.dependency.com.google.code.gson.gson.jar.path}"/>
    </externalclasses>

    <rename logfile="${project.build.directory}/${project.build.finalName}_renamelog.xml">
      <keep>
        <class classes="none" methods="none" fields="none">
            <patternset>
                <include name="org.example."/>
            </patternset>
        </class>
      </keep>
    </rename>
  </yguard>
</tasks>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

在这个配置中,前两个 <property 定义了两个属性,在ant中可以通过 ${project.build.directory} 引用Maven配置,并不是所有配置都能生效,可以通过下面的方式简单验证:

<target>
  <echo message="basedir: ${basedir}"/>
  <echo message="project.build.directory: ${project.build.directory}"/>
</target>
  • 1
  • 2
  • 3
  • 4

上面任务会输出以下内容(和所在项目有关):

main:
     [echo] basedir: D:\GitLab\module-parent\module-yuard
     [echo] project.build.directory: D:\GitLab\module-parent\module-yuard\target
  • 1
  • 2
  • 3

上面配置第三个 <move 实际上给 maven 默认打包出来的 jar 改了个名字,从.jar 后缀改成了 .jar.unobf

再下面一个 <property 中通过 refid="maven.runtime.classpath" 指定了运行时的类路径,可以用下面方式查看类路径的信息:

<property name="runtime_classpath" refid="maven.runtime.classpath"/>
<echo message="runtime_classpath: ${runtime_classpath}"/>
  • 1
  • 2

关于 refid="maven.runtime.classpath" 更多的信息可以看下面文档
https://maven.apache.org/plugins/maven-antrun-plugin/examples/classpaths.html

输出结果如下:

main:
     [echo] runtime_classpath: D:\GitLab\module-parent\module-yuard\target\classes;D:\GitLab\module-parent\module-a\target\module-a-1.0-SNAPSHOT.jar;D:\GitLab\module-parent\module-b\target\module-b-1.0-SNAPSHOT.jar;D:\GitLab\module-parent\module-c\target\module-c-1.0-SNAPSHOT.jar;D:\Dev\.m2\repository\com\yworks\yguard\4.1.1-SNAPSHOT\yguard-4.1.1-SNAPSHOT.jar;D:\Dev\.m2\repository\com\yworks\annotation\4.1.1-SNAPSHOT\annotation-4.1.1-SNAPSHOT.jar;D:\Dev\.m2\repository\org\ow2\asm\asm\9.2\asm-9.2.jar;D:\Dev\.m2\repository\org\apache\ant\ant\1.10.12\ant-1.10.12.jar;D:\Dev\.m2\repository\org\apache\ant\ant-launcher\1.10.12\ant-launcher-1.10.12.jar;D:\Dev\.m2\repository\cn\hutool\hutool-all\5.7.22\hutool-all-5.7.22.jar
  • 1
  • 2

这里正好结合下面的 <externalclasses> 看看,通过 debug yGuard,可以看到注入的实际地址:
在这里插入图片描述
可以看到类路径最后一个是 D:\GitLab\module-parent\module-yuard\${maven.dependency.com.google.code.gson.gson.jar.path},这个明显没有对应的 jar,这种写法是无法自动解析为对应jar包的,使用Maven时需要注意,官方示例和文档中也有类似的错误。

再下面的 <taskdef 就是 ant 扩展任务的定义,属于固定写法,再往下的 <yguard> 就是 yGuard 主要的配置部分了。

yGuard部分通过<inoutpair in="${project.jar.unobf}" out="${project.jar}" />定义要处理的jar包,in是输入,out是输出,这两个名字可以一样,相当于会覆盖。<inoutpair>可以配置多个,但是maven执行的机制导致这里能被有效混淆的只能有1个,后续实现的多模块混淆是利用了Maven生命周期的一些特点实现的。

<externalclasses>部分是外部 jar 依赖,运行时用到的可以配置到这里,可以一个个指定,也可以像上面文档直接指定 maven 的运行时类路径。

<rename>是本系列的重点,上面示例中使用的 <keep>配置具体的混淆规则,混淆规则中主要使用 <class>配置,一般情况下不需要细致的具体的方法进行配置,通过 <class> 的属性配置一般的通用规则即可。

针对 <class>元素的 classesmethodsfields 三个属性,遵循以下表格的规则(-代表被混淆,*代表保留)。

Value/Visibilitypublicprotectedfriendlyprivate
none----
public*---
protected**--
friendly***-
private****

例如当配置 classes="public" 时,所有 public class XXX 会保持原样,其他类型的会被混淆,当 classes="private 时,所有类名都会保留,方法和字段也是类似的,上面示例中 <class classes="none" methods="none" fields="none">,相当于类名、方法、字段全部被混淆,都不被保留。

上面配置 <include name="org.example."/> 时,包名最后的 . 必须包含,你还可以使用 ant 中的 *** 匹配单级或多级,通过 ? 匹配单个字符。

<class> 可以配置很多个:

<class classes="none" methods="none" fields="none">
    <patternset>
        <include name="org.example."/>
        <include name="org.example.c.util.FileUtil"/>
    </patternset>
</class>
<class classes="private" methods="private" fields="private">
    <patternset>
        <include name="org.example.c."/>
    </patternset>
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

上面相当于两部分规则,第一部分是完全混淆的代码,第二部分是完全保留的代码,当配置多块时,<patternset> 部分配置的类不能重叠。上面部分配置中存在重叠的部分,首先 org.example. 包含了 org.example.c.org.example.c.util.FileUtil,上面配置想法是把 org.example. 下面的代码都混淆,把 org.example.c 下面的 FileUtil 混淆。但是不混淆 org.example.c.,真正执行的结果是 org.example.c. 都没有被混淆(如下图),但是a和b被混淆了。
在这里插入图片描述
如果把上面两部分 <class>顺序调整一下,结果还是一样,虽然看了yGuard源码,但是没找到明确的规则,目前猜测是混淆低的优先级更高。如果把上面两个 <class><patternset> 调换,所有代码都不会被混淆。

因此当你有多组配置时,指定的范围要尽可能的小,而且所有配置要互斥,不能互相包含,想要实现想要的效果,需要按下面的方式进行配置:

<class classes="none" methods="none" fields="none">
    <patternset>
        <include name="org.example."/>
        <include name="org.example.c.util.FileUtil"/>
    </patternset>
</class>
<class classes="private" methods="private" fields="private">
    <patternset>
        <include name="org.example.c."/>
        <exclude name="org.example.c.util.FileUtil"/>
    </patternset>
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述
这里在优先级更高的规则中通过 <exclude name="org.example.c.util.FileUtil"/> 进行了排除,如果你的混淆配置更复杂,优先级无法确定时,上面的配置粒度仍然不够小,应该把 <include name="org.example."/> 变得更具体,如下:

<class classes="none" methods="none" fields="none">
    <patternset>
        <include name="org.example.a."/>
        <include name="org.example.b."/>
        <include name="org.example.c.util.FileUtil"/>
    </patternset>
</class>
<class classes="private" methods="private" fields="private">
    <patternset>
        <include name="org.example.c."/>
        <exclude name="org.example.c.util.FileUtil"/>
    </patternset>
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

当你遇到更难解决的情况时,有可能是指定所有具体类的规则。

了解的 yGuard 这部分配置后,接下来就可以进行多模块配置了,多模块配置中也会提供一个示例项目,方便跟着操作研究。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/830983?site
推荐阅读
相关标签
  

闽ICP备14008679号