0
点赞
收藏
分享

微信扫一扫

混淆技术研究笔记(三)多模块混淆

logo

示例项目: https://github.com/abel533/yguard-modules-parent

假设有如下多模块项目:

module-parent
├─module-a
├─module-b
└─module-c

混淆技术研究笔记(一)常见工具介绍 中提到,默认只能使用单模块混淆,每个模块构建时的上下文只有自己,无法对其他模块进行处理,虽然 <<inoutpair/> 能配置多个,比如 a 依赖 b,b 依赖 c 的情况,如果配置到 a 中,在 a 中对a,b,c进行混淆,确实能实现对 jar 包内容的混淆,但是当执行 mvn clean deploy 命令时,这种混淆只对 a 自己有效。

主要的原因和 Maven 的生命周期有关,在 module-parent 这一级执行 mvn clean deploy 发布时,Maven会根据模块依赖顺序计算构建的顺序,第一个构建的模块会走完全部的生命周期后,再对第二个模块进行相同的处理,依次执行完全部的模块。

在 a 中配置多个时,当 a 模块执行时,其他模块构建完就已经发布了,对发布后的 b,c 再进行混淆已经没有意义。

该如何实现呢?

Maven在package打包时有个特性,如果源码没有变化就不会再次进行编译,已经构建的 jar 不会被覆盖,Maven只检测源码的变化,不会检测 jar 包的变化,从这点入手就能实现多模块混淆。 在这里插入图片描述 上面这种方式执行时,需要避免混淆插件执行两次,因此最好的办法就是在多模块基础上增加一个新的模块,例如 module-yguard,变成如下结构:

module-parent
├─module-a
├─module-b
├─module-c
└─module-yguard

module-yguard中添加a,b,c的依赖,保证最后执行,在module-yguard中配置yGuard插件,在配置中对a,b,c进行混淆,并且在执行发布命令时通过 -pl !module-yguard 排除混淆模块的构建,避免多次混淆。 在这里插入图片描述 在构建时分成两步不会增加更多的时间,也没有变的更复杂,通过这种方式就实现了多模块混淆。

下面是本文示例的配置:

<tasks>
    <property name="runtime_classpath" refid="maven.runtime.classpath"/>

    <taskdef name="yguard" classname="com.yworks.yguard.YGuardTask" classpath="${runtime_classpath}"/>
    <yguard>
        <inoutpair in="..\module-b\target\module-b-${project.version}.jar"
                   out="..\module-b\target\module-b-${project.version}.jar"/>
        <inoutpair in="..\module-c\target\module-c-${project.version}.jar"
                   out="..\module-c\target\module-c-${project.version}.jar"/>
        <inoutpair in="..\module-a\target\module-a-${project.version}.jar"
                   out="..\module-a\target\module-a-${project.version}.jar"/>

        <attribute name="SourceFile, LineNumberTable, LocalVariableTable">
            <patternset>
                <include name="org.example.**"/>
            </patternset>
        </attribute>
        <rename logfile="${project.build.directory}/yguard.log.xml"
                replaceClassNameStrings="true">
            <keep>
                <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>
            </keep>
            <property name="naming-scheme" value="best"/>
            <property name="language-conformity" value="illegal"/>
            <property name="overload-enabled" value="true"/>
        </rename>

        <externalclasses>
            <pathelement path="${runtime_classpath}"/>
        </externalclasses>
    </yguard>
</tasks>

混淆后的代码效果: 在这里插入图片描述 使用的jadx反编译工具,一次可以同时查看多个jar。

在这个混淆示例中,相当于只暴露了 UserServiceUser 接口,如果是支持ioc注入的情况下,可以注入 UserService 接口进行使用,但是其他被混淆的就不方便被使用。

虽然这里很简单,但是我实际要处理的这个项目有4级多模块,总共能打包七十几个模块,而且要和旧版打包方式接近,因此耗时很久,最难的就是上一节介绍的,如果有多种混淆配置(<class>),多种配置之间的排除会很麻烦。

到这里就解决了一个难题,但是更难的还在后头,如何在混淆代码的基础上实现反篡改

举报

相关推荐

0 条评论