Java加密解密class文件,使用classLoader动态解密class文件

在日常开发中,可能会遇到要对系统中比较敏感的代码进行保护,那么下面就总结一下保护源码的方法中最简单的方式,即文件加密

首先,加密和解密的大致思想是:加密无非就是对class文件进行异或一下,解密呢,那就是再对class文件异或回来即可。

加密后的文件如果想要用到的话,就需要classLoader动态加载进来,具体实现请移步至:https://blog.csdn.net/qq_28082757/article/details/81481981


/**
 * 加解密类
 */
public class EdCipher {

    private String encryptFolder = "encrypt";

    /**
     * 加密方法
     * @param name 需要加密的文件名
     */
    public void encryptClass(String name) {
        String path = getFilePath(name);
        // classFile为待加密的class文件
        File classFile = new File(path);
        if (!classFile.exists()) {
           // TODO 如果文件不存在,做相应的处理。一般情况下都是抛出异常;
        } else {
           // folder 是准备在待加密的文件也就是classFIle的同级目录下创建一个文件夹,里面放着加密后的文件
            File folder = new File(classFile.getParent() + File.separator + encryptFolder);
            if (!folder.exists()) {
                folder.mkdirs();
            }
        }
        // cipheredClass 为加密后文件的全路径文件名
        String cipheredClass = classFile.getParent() + File.separator + encryptFolder + File.separator + classFile.getName();
        try (
                FileInputStream fileInputStream = new FileInputStream(classFile);
                BufferedInputStream bis = new BufferedInputStream(fileInputStream);
                FileOutputStream fileOutputStream = new FileOutputStream(cipheredClass);
                BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream)
        ) {
            int data;
            while ((data = bis.read()) != -1) {
                bos.write(data ^ 0xFF);
            }
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

    // 现在将原来未加密的文件删除
        classFile.delete();
        // 这里在文件后面加了一个“en”,最后生成的文件就是xxx.classen,这样做的目的是为了在启动服务器的时候,tomcat会自动检查classespath下的class文件,如果我不加上一个“en”,那么改加密文件就会被tomcat扫描到。如果被扫描到了,但是它又是一个被加密后的文件,头部信息被修改了,那么tomcat就会报错,启动不起来。这算是一个小技巧。
        File oldFile = new File(path + "en");
        if (oldFile.exists()) {
            oldFile.delete();
        }
        File cipheredFile = new File(cipheredClass);
        cipheredFile.renameTo(oldFile);
        cipheredFile.getParentFile().delete();
    }

    /**
     * 解密方法
     * @param name 需要解密的文件名
     */
    protected byte[] decryptClass(String name) {
        String path;
        if (!name.contains(".class")) {
            path = getDefFilePath(name);
        } else {
            path = name;
        }
        File encryptedClassFile = new File(path);
        if (!encryptedClassFile.exists()) {
            System.out.println("decryptClass() File:" + path + " not found!");
            return null;
        }
        byte[] result = null;
        BufferedInputStream bis = null;
        ByteArrayOutputStream bos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(encryptedClassFile));
            bos = new ByteArrayOutputStream();
            int data;
            while ((data = bis.read()) != -1) {
                bos.write(data ^ 0xFF);
            }
            bos.flush();
            result = bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

   //获取加密前文件的绝对路径
    private String getFilePath(String name) {
        String path;
        String str = name.substring(name.lastIndexOf(".") + 1, name.length()) + ".class";
        path = EdCipher.class.getResource(str).toString();
        path = path.substring(path.indexOf("file:/") + "file:/".length(), path.length());
        if (System.getProperty("os.name").toUpperCase().contains("LINUX")) {
            path = File.separator + path;
        }
        return path;
    }

   //获取加密后文件的绝对路径 
    private String getDefFilePath(String name) {
        String path;
        String str = name.substring(name.lastIndexOf(".") + 1, name.length()) + ".classen";
        path = EdCipher.class.getResource(str).toString();
        path = path.substring(path.indexOf("file:/") + "file:/".length(), path.length());
        return path;
    }

   // 测试
    public static void main(String[] args) {
        EdCipher edCipher = new EdCipher();
        edCipher.encryptClass(args[0]);
    }
}

如果要想在Ant打包的时候,就加密文件,就需要在build.xml配置文件中调用该类的Main方法即可;

<!-- 加密 -->
<target name="encrypt">
    <java classname="EdCipher" failonerror="true">
        <classpath refid="classpath.run"/>
        <arg line="需要加密的文件的包名+文件名"/>
    </java>
</target>

踏实一些,不要着急,你想要的,岁月都会给你。

猜你喜欢

转载自blog.csdn.net/qq_28082757/article/details/81481215