springboot xjar 安全加密运行工具

2021年4月15日 7点热度 0条评论 来源: 1057718341_h

这里写自定义目录标题

xjar安全加密运行工具

GitHub: https://github.com/core-lib/xjar

Spring Boot JAR 安全加密运行工具, 同时支持的原生JAR.
基于对JAR包内资源的加密以及拓展ClassLoader来构建的一套程序加密启动, 动态解密运行的方案, 避免源码泄露以及反编译.

功能特性
无代码侵入, 只需要把编译好的JAR包通过工具加密即可.
完全内存解密, 降低源码以及字节码泄露或反编译的风险.
支持所有JDK内置加解密算法.
可选择需要加解密的字节码或其他资源文件.
支持Maven插件, 加密更加便捷.
动态生成Go启动器, 保护密码不泄露.

创建项目

源码: https://gitee.com/starsky20/starsky-xjar.git

1、使用idea创建一个java项目,然后引入xjar需要的jar包。
打开idea, 点击菜单 File-》new-》Project-》选择maven项目-》


创建完成如下:

编写代码

pom.xml 引入xjar依赖包:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>demo-xjar</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- 添加 XJar 依赖 -->
        <dependency>
            <groupId>com.github.core-lib</groupId>
            <artifactId>xjar</artifactId>
            <version>4.0.2</version>
            <!-- <scope>test</scope> -->
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.5</version>
        </dependency>
    </dependencies>

    <!-- 设置 jitpack.io 仓库 -->
    <repositories>
        <repository>
            <id>jitpack.io</id>
            <url>https://jitpack.io</url>
        </repository>
    </repositories>

</project>

2、编写代码,生成加密文件
参考文档:https://www.cnblogs.com/-flq/p/14297274.html
package com.starsky.xjar;

import io.xjar.XKit;
import io.xjar.boot.XBoot;
import io.xjar.key.XKey;
import org.apache.commons.lang.StringUtils;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @desc:xjar 加密工具,针对java开发项目jar包进行加密,jar加密后,大小会翻倍,同时swagger无法访问,接口暂时未发现问题
 * @author: wangsh
 * @time: 2021/4/15 9:34
 */
public class XjarEncryUtil {

    public static void main(String[] args) {
        createJFrame();
    }

    /**
     * 创建面板,这个类似于 HTML 的 div 标签,我们可以创建多个面板并在 JFrame 中指定位置,面板中我们可以添加文本字段,按钮及其他组件。
     */
    public static void createJFrame() {
        // 创建 JFrame 实例
        JFrame frame = new JFrame("XJar加密,防止反编译");
        // 设置窗口大小
        frame.setSize(600, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //创建面板,这个类似于 HTML 的 div 标签,可以创建多个面板并在 JFrame 中指定位置,
        // 面板中可以添加文本字段,按钮及其他组件。
        JPanel panel = new JPanel();
        // 添加面板
        frame.add(panel);
        //调用用户定义的方法并添加组件到面板
        addComponents(panel);
        // 设置界面可见
        frame.setVisible(true);
    }

    /**
     * 调用用户定义的方法并添加组件到面板
     */
    private static void addComponents(JPanel panel) {
        //布局部分我们这边不多做介绍,这边设置布局为 null
        panel.setLayout(null);

        // 创建 需要加密的jar JLabel
        JLabel fromLabel = new JLabel("选择加密的jar:");
        fromLabel.setBounds(10, 20, 120, 30);
        panel.add(fromLabel);

        //用于记录未加密jar的文本域
        final JTextField fromText = new JTextField(20);
        fromText.setBounds(100, 20, 300, 30);
        panel.add(fromText);

        // 创建选择按钮
        JButton fromButton = new JButton("选择");
        fromButton.setBounds(420, 20, 80, 30);
        panel.add(fromButton);

        // 加密后jar要保存的位置
        JLabel toLabel = new JLabel("选择保存位置:");
        toLabel.setBounds(10, 50, 120, 30);
        panel.add(toLabel);

        //文本域用于记录保存路径
        final JTextField toText = new JTextField(20);
        toText.setBounds(100, 50, 300, 30);
        panel.add(toText);

        // 创建选择按钮
        JButton toButton = new JButton("选择");
        toButton.setBounds(420, 50, 80, 30);
        panel.add(toButton);

        // 输入密码的文本域
        JLabel passwordLabel = new JLabel("加密密码:");
        passwordLabel.setBounds(10, 80, 80, 30);
        panel.add(passwordLabel);

        //这个类似用于输入的文本域,但是输入的信息会以点号代替,用于包含密码的安全性
        final JPasswordField passwordText = new JPasswordField(20);
        passwordText.setBounds(100, 80, 300, 30);
        panel.add(passwordText);

        // 创建开始按钮
        JButton startButton = new JButton("加密");
        startButton.setBounds(100, 110, 80, 30);
        panel.add(startButton);
        // 创建开始按钮
        JButton endButton = new JButton("解密");
        endButton.setBounds(200, 110, 80, 30);
        panel.add(endButton);

        //日志显示框
        final JTextArea textArea = new JTextArea("");
        textArea.setBounds(10, 150, 550, 150);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        panel.add(textArea);

        //选择jar按钮监听事件
        fromButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {  //按钮点击事件
                JFileChooser chooser = new JFileChooser();             //设置选择器
                chooser.setMultiSelectionEnabled(false);             //设为单选
                int returnVal = chooser.showOpenDialog(null);        //是否打开文件选择框
                if (returnVal == JFileChooser.APPROVE_OPTION) {          //如果符合文件类型
                    String filepath = chooser.getSelectedFile().getAbsolutePath();      //获取绝对路径
                    if (!".jar".equals(filepath.substring(filepath.length() - 4))) {
                        JOptionPane.showMessageDialog(null, "文件格式不正确,请选择jar文件!", "文件格式错误", JOptionPane.ERROR_MESSAGE);
                    } else {
                        fromText.setText(filepath);
                    }
                    System.out.println(filepath);
                }
            }
        });

        //选择加密后jar保存路径按钮监听事件
        toButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {  //按钮点击事件
                JFileChooser chooser = new JFileChooser();             //设置选择器
                chooser.setMultiSelectionEnabled(false);             //设为单选
                chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); //设置只选目录
                chooser.setDialogTitle("选择加密后jar保存位置");
                int returnVal = chooser.showOpenDialog(null);        //是否打开文件选择框
                if (returnVal == JFileChooser.APPROVE_OPTION) {          //如果符合文件类型
                    String filepath = chooser.getSelectedFile().getAbsolutePath();      //获取绝对路径
                    toText.setText(filepath);
                    System.out.println(filepath);
                }
            }
        });

        //选择开始径按钮的监听事件
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String fromJarPath = fromText.getText();
                String toJarPath = toText.getText() + "\\encrypt" + getNowDateTime() + ".jar";
                String password = new String(passwordText.getPassword());
                System.out.println("fromJarPath=" + fromJarPath);
                System.out.println("toJarPath=" + toJarPath);
                System.out.println("password=" + password);
                if (StringUtils.isEmpty(fromJarPath)) {
                    JOptionPane.showMessageDialog(null, "jar文件不能为空!", "jar文件不能为空!", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                if (StringUtils.isEmpty(toJarPath)) {
                    JOptionPane.showMessageDialog(null, "保存路径不能为空!", "保存路径不能为空!", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                if (StringUtils.isEmpty(toJarPath)) {
                    JOptionPane.showMessageDialog(null, "请输入加密的密码!", "密码不能为空!", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                //打印输入日志
                StringBuilder builder = new StringBuilder();
                builder.append("fromJarPath=" + fromJarPath + "\n");
                builder.append("toJarPath=" + toJarPath + "\n");
                textArea.setText(builder.toString());
                //开始加密文件
                encryptJar(fromJarPath, toJarPath, password);
                textArea.append("jar加密成功!\n请测试接口是否正常(注意:Swagger不可用)");
            }
        });
        //选择开始径按钮的监听事件
        endButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String fromJarPath = fromText.getText();
                String toJarPath = toText.getText() + "\\encrypt" + getNowDateTime() + ".jar";
                String password = new String(passwordText.getPassword());
                System.out.println("fromJarPath=" + fromJarPath);
                System.out.println("toJarPath=" + toJarPath);
                System.out.println("password=" + password);
                if (StringUtils.isEmpty(fromJarPath)) {
                    JOptionPane.showMessageDialog(null, "jar文件不能为空!", "jar文件不能为空!", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                if (StringUtils.isEmpty(toJarPath)) {
                    JOptionPane.showMessageDialog(null, "保存路径不能为空!", "保存路径不能为空!", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                if (StringUtils.isEmpty(toJarPath)) {
                    JOptionPane.showMessageDialog(null, "请输入加密的密码!", "密码不能为空!", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                //打印输入日志
                StringBuilder builder = new StringBuilder();
                builder.append("fromJarPath=" + fromJarPath + "\n");
                builder.append("toJarPath=" + toJarPath + "\n");
                textArea.setText(builder.toString());
                //开始加密文件
                decryptJar(fromJarPath, toJarPath, password);
                textArea.append("jar加密成功!\n请测试接口是否正常(注意:Swagger不可用)");
            }
        });
    }

    /**
     * 获取当前格式化时间的方法
     */
    private static String getNowDateTime() {
        String dateNow = "";
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        Date date = new Date();
        dateNow = format.format(date);
        return dateNow;
    }

    /**
     * jar包加密,防止反编译
     * 此编译方式在运行jar包时需要输入密码
     * 运行方式一 :
     * // 命令行运行JAR 然后在提示输入密码的时候输入密码后按回车即可正常启动
     * java -jar /path/to/encrypted.jar
     * 运行方式二:
     * // 也可以通过传参的方式直接启动,不太推荐这种方式,因为泄露的可能性更大!
     * java -jar /path/to/encrypted.jar --xjar.password=PASSWORD
     * 运行方式三:
     * // 对于 nohup 或 javaw 这种后台启动方式,无法使用控制台来输入密码,推荐使用指定密钥文件的方式启动
     * nohup java -jar /path/to/encrypted.jar --xjar.keyfile=/path/to/xjar.key
     * xjar.key 文件说明:
     * 格式:
     * password: PASSWORD
     * algorithm: ALGORITHM
     * keysize: KEYSIZE
     * ivsize: IVSIZE
     * hold: HOLD
     * 参数说明:
     * password    密码  无   密码字符串
     * algorithm   密钥算法    AES     支持JDK所有内置算法,如AES / DES ...
     * keysize     密钥长度    128     根据不同的算法选取不同的密钥长度。
     * ivsize  向量长度    128     根据不同的算法选取不同的向量长度。
     * hold    是否保留    false   读取后是否保留密钥文件。
     *
     * @param fromJarPath 需要加密的jar
     * @param toJarPath   加密后的jar
     * @param password    加密密码
     */
    public static void encryptJar(String fromJarPath, String toJarPath, String password) {

        try {
            // Spring-Boot Jar包加密
            XKey xKey = XKit.key(password);
            XBoot.encrypt(fromJarPath, toJarPath, xKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * jar包解密
     *
     * @param fromJarPath 已通过Xjar加密的jar文件路径
     * @param toJarPath   解密后的jar文件
     * @param password    密码
     */
    public static void decryptJar(String fromJarPath, String toJarPath, String password) {
        try {
            XKey xKey = XKit.key(password);
            XBoot.decrypt(fromJarPath, toJarPath, xKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

以上编写完成后可以直接运行main,结果如下:

以上是通过工具直接运行结果,如果我们需要将项目放在其他地方使用,很不方便,故需要将项目打包成jar包运行,下面介绍通过idea将maven项目打包成可运行的jar包。

idea将maven项目打包成可运行的jar包

选择 File-》Project Structure
然后再弹出框中选择 Atifacts -》“+“ -》from modules with dependcents


这里选择main函数运行java类,manifest.mf 文件目录这里 需要将src目录后面的文件夹取掉, 点击ok确认后如下:

以上表示jar包基本配置完成,下来就开始生产jar包。
选择build-》Artifacts


选择jar包-》build即可生成jar包。build是指首次编译,rebuild是首次编译后使用的, 编译后生产jar包如下:

进入到jar包目录

通过cmd命令行运行 java -jar xxx.jar , 如下:

运行后,在弹出框选择需要加密的jar文件、输出加密目录、加密密码。

加密后再d盘生产一个加密文件、xjar.go、xjar_agentable.go .

以上表示加密完成,下面介绍如下运行加密后的文件。

运行加密jar文件

1、安装编译脚本

安装go语言环境下载地址:https://studygolang.com/dl

我这里使用windows开发,下载go1.16.3.windows-amd64.msi , 下载完成直接安装即可。
安装后验证是否安装成功,打开cmd,执行 go env

2、进入到生成加密文件目录,执行编译
go build xjar.go

编译后生产一个xjar.exe文件,后面需要通过该文件运行密码jar包。

通过步骤2加密成功后XJar会在输出的JAR包同目录下生成一个名为 xjar.go 的的Go启动器源码文件.
将 xjar.go 在不同的平台进行编译即可得到不同平台的启动器可执行文件, 其中Windows下文件名为 xjar.exe 而Linux下为 xjar.
用于编译的机器需要安装 Go 环境, 用于运行的机器则可不必安装 Go 环境, 具体安装教程请自行搜索.
由于启动器自带JAR包防篡改校验, 故启动器无法通用, 即便密码相同也不行.

  1. 启动运行

xjar java -jar /path/to/encrypted.jar

xjar javaw -jar /path/to/encrypted.jar

nohup xjar java -jar /path/to/encrypted.jar

centos 安装go

1.下载二进制包

wget https://dl.google.com/go/go1.11.4.linux-amd64.tar.gz

2.将下载的二进制包解压至 /usr/local目录

tar -C /usr/local -xzf go1.4.linux-amd64.tar.gz
3.打开/etc/profile文件

sudo vim /etc/profile
4.将 /usr/local/go/bin 目录添加至PATH环境变量,在/etc/profile文件底部添加如下行

export PATH=$PATH:/usr/local/go/bin
5.应用修改的配置

source /etc/profile
如上则环境配置完成,执行测试看是否安装成功

输入 go version能正常显示版本号,正常安装。

以上表示go安装成功

2、将加密jar包、xjar.go、xjar_agentable.go 上传到服务器。


执行命令: ./xjar java -jar encrypt20210415162050.jar

springboot项目集成xjar 加密工具

源码:https://gitee.com/starsky20/springboot-xjar.git

通过idea创建一个springboot项目,然后引入xjar依赖包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>starsky-xjar</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>starsky-xjar</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring.boot.version>2.0.7</spring.boot.version>
        <spring.boot.admin.version>2.0.3</spring.boot.admin.version>
        <spring.cloud.version>Finchley.SR2</spring.cloud.version>
        <spring.cloud.alibaba.version>2.0.3.RELEASE</spring.cloud.alibaba.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 添加 XJar 依赖 -->
        <dependency>
            <groupId>com.github.core-lib</groupId>
            <artifactId>xjar</artifactId>
            <version>4.0.2</version>
            <!-- <scope>test</scope> -->
        </dependency>
        <dependency>
            <groupId>com.github.core-lib</groupId>
            <artifactId>loadkit</artifactId>
            <version>v1.0.0</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.github.core-lib</groupId>
                <artifactId>xjar-maven-plugin</artifactId>
                <version>4.0.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                        </goals>
                        <!--可以改成 install-->
                        <phase>package</phase>
                        <configuration>
                            <password>io.xjar</password>
                            <!-- 需要加密的资源路径表达式 -->
                            <includes>
                                <include>com/starsky/**</include>
                                <include>mapper/*Mapper.xml</include>
                                <include>config/**</include>
                            </includes>
                            <!-- 无需加密的资源路径表达式 -->
                            <excludes>
                                <exclude>static/**</exclude>
                                <exclude>templates/**</exclude>
                                <exclude>resources/**</exclude>
                                <exclude>META-INF/resources/**</exclude>
                            </excludes>
                            <!-- 目标jar存放目录及目标jar名称,也可以用表达式(参考官网) -->
                            <targetJar>web-app.jar</targetJar>
                           <!-- <targetJar>你的jar包名字</targetJar>-->
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <!-- 资源目录 -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <!-- 资源根目录排除各环境的配置,防止在生成目录中多余其它目录 -->
                <excludes>
                    <exclude>application.properties</exclude>
                    <exclude>bootstrap-dev.yml</exclude>
                    <exclude>bootstrap-prod.yml</exclude>
                    <exclude>bootstrap-test.yml</exclude>
                </excludes>
                <filtering>true</filtering>
            </resource>
            <!--激活指定文件-->
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>application.properties</include>
                </includes>
            </resource>
            <!--打包java目录-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

    <!-- 设置 jitpack.io 仓库 -->
    <repositories>
        <repository>
            <id>jitpack.io</id>
            <url>https://jitpack.io</url>
        </repository>
    </repositories>
    <!-- 设置 jitpack.io 插件仓库 -->
    <pluginRepositories>
        <pluginRepository>
            <id>jitpack.io</id>
            <url>https://jitpack.io</url>
        </pluginRepository>
    </pluginRepositories>

</project>

注意事项

  1. 不兼容 spring-boot-maven-plugin 的 executable = true 以及 embeddedLaunchScript
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <!-- 需要将executable和embeddedLaunchScript参数删除, 目前还不能支持对该模式Jar的加密!后面可能会支持该方式的打包. 
    <configuration>
        <executable>true</executable>
        <embeddedLaunchScript>...</embeddedLaunchScript>
    </configuration>
    -->
</plugin>

插件集成
Maven项目可通过集成 xjar-maven-plugin 以免去每次加密都要执行一次上述的代码, 随着Maven构建自动生成加密后的JAR和Go启动器源码文件.
xjar-maven-plugin GitHub: https://github.com/core-lib/xjar-maven-plugin

对于Spring Boot 项目或模块, 该插件要后于 spring-boot-maven-plugin 插件执行, 有两种方式:
将插件放置于 spring-boot-maven-plugin 的后面, 因为其插件的默认 phase 也是 package
将插件的 phase 设置为 install(默认值为:package), 打包命令采用 mvn clean install

也可以通过Maven命令执行
mvn xjar:build -Dxjar.password=io.xjar
mvn xjar:build -Dxjar.password=io.xjar -Dxjar.targetDir=/directory/to/save/target.xjar

但通常情况下是让XJar插件绑定到指定的phase中自动执行, 这样就能在项目构建的时候自动构建出加密的包.

mvn clean package -Dxjar.password=io.xjar
mvn clean install -Dxjar.password=io.xjar -Dxjar.targetDir=/directory/to/save/target.xjar

强烈建议
强烈建议不要在 pom.xml 的 xjar-maven-plugin 配置中写上密码,这样会导致打包出来的 xjar 包中的 pom.xml 文件保留着密码,极其容易暴露密码!强烈推荐通过 mvn 命令来指定加密密钥!

打包运行

进入到项目目录,执行命令:
mvn clean package -Dxjar.password=123456789 -Dmaven.test.skip=true
这里打包排除test测试相关代码不打包。


打包完成如下:

进入到打包目录,执行编译 go build xjar.go , 执行后会生成一个xjar.exe文件

通过cmd命令行运行如下:

针对springboot项目加密后,swagger接口 不能通过页面访问,加密后jar包体积大约增加2倍。
至于项目部署是否需要加密处理,根据实际情况进行调整。

实际部署项目为例测试:

1、未加密swagger接口:

未加密jar包,访问swagger接口,可以查看所有接口。

2、加密后,swagger接口访问测试:

可以看到,加密直接访问swagger接口没有任何结果。

3、通过gateway网关测试swagger接口:

通过gateway访问加密服务swagger可以。

通过反编译工具查看加密的jar包

1、正常jar包,通过反编译工具可直接查看,如下:

生成未加密的jar包,通过反编译工具可以直接查看源码,没有任何安全错误,容易被窃取。

2、通过xjar进行加密jar包,如下:

可以看到,我们查看加密后的class文件,直接提示class文件无效,不能直接查看源码了。

    原文作者:1057718341_h
    原文地址: https://blog.csdn.net/seashouwang/article/details/115728095
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。