专栏首页技术趋势如何实现对java生成的.class加密?

如何实现对java生成的.class加密?

背景

在以往很多商业的系统,除了知识产权以外很多代码都是加密所以我们很难去直接去读取原码,并且这样通过加密.class文件有效的对自已的产品或系统进行保护。

实现原理

生成.class后将原来的.class进行加密或者取反,因为.class里面最终生成的是二进制0101这类的二进制代码,当然也可以通过一些md5或一些RES等加密方式进行加密;以下案例是参考网上一些案例而来,参考文章在文末,其实原理一样。解密的时候通过去实现java的classLoader将原来的.findClass 进行改造,就可以实现针对性的加密(tomcat实现打破双亲委派也是这样的哦~),其实很简单参考如下:

代码下载地址:https://gitee.com/hong99/jdk8.git

实现代码

package com.encryption.demo;

/**
 * @description: 测试方法
 * @author hong
 * @date
 * @version 1.0
 */
public class TestContent {
    public void hong(){
        System.out.println("my name is hong!!!");
    }
}
package com.encryption.demo;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 加解密工具
 */
public class EncryptionUtils extends ClassLoader{




    /**统一加密/解密 密钥 **/
    private int password = 0xFF;

    private static String parentPath ="D://";

    /**
     * 加密方法
     * @param pathUrl 类名称
     */
    public void encryptionClass(String pathUrl){
        if(null==pathUrl || "".equals(pathUrl)){
            System.out.println("路径不能为空!");
            return;
        }
        String path =new File(pathUrl).getAbsolutePath();

        //获取文件
        File file = new File(path);
        if(!file.exists()){
            throw new NoClassDefFoundError("没有找到文件!");
        }
        //获取文件夹目录
        File awaitFileFolder = new File(file.getParent() + File.separator);
        //不存在则创建目录
        if(!awaitFileFolder.exists()){
            awaitFileFolder.mkdirs();
        }
        File encryptFolder = new File(awaitFileFolder.getParent() + File.separator );
        if (!encryptFolder.exists()) {
            encryptFolder.mkdirs();
        }
        //加密后文件指定存放目录
// String encryptedFile = file.getParent() + File.separator + File.separator + file.getName();
        String encryptedFile = parentPath + file.getName();
        try (
                FileInputStream fileInputStream = new FileInputStream(file);
                BufferedInputStream bis = new BufferedInputStream(fileInputStream);
                FileOutputStream fileOutputStream = new FileOutputStream(encryptedFile);
                BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream)
        ) {
            // 加密
            int data;
            while ((data = bis.read()) != -1) {
                bos.write(data ^ password);
            }
            bos.flush();
        } catch (IOException e) {
            System.out.println("加密异常!");
            e.printStackTrace();
        }
        // 现在将原来未加密的文件删除
       // awaitFileFolder.delete();

        // 先获取加密前文件绝对路径名,然后修改后缀,再创建File对象
        File oldFile = new File(parentPath +file.getName()+ "hong");
        // 删除未加密前的文件
// if (oldFile.exists()) {
// oldFile.delete();
// }
        // 根据加密后的文件创建File对象
        File newEncryptedFile = new File(encryptedFile);
        // 将加密后的对象重命名,这时加密后的文件就把加密前的文件替换掉了,这就是为什么刚开始加密后的文件需要单独放的原因
        newEncryptedFile.renameTo(oldFile);
        // 删除之前的加密文件夹下面的加密文件
        newEncryptedFile.getParentFile().delete();
    }

    /**
     * 解密方法
     * @param pathUrl 需要解密的文件名
     */
    protected byte[] decryptClass(String pathUrl) {
        String path;
        if (!pathUrl.contains(".class")) {
            path = new File(pathUrl).getAbsolutePath();
        } else {
            path = pathUrl;
        }
        //获取待解密文件
        File decryptClassFile = new File(path);
        if (!decryptClassFile.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(decryptClassFile));
            bos = new ByteArrayOutputStream();
            // 解密
            int data;
            while ((data = bis.read()) != -1) {
                bos.write(data ^ password);
            }
            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;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes = decryptClass(name);
        int length = bytes ==null?0:bytes.length;
        return defineClass("com.encryption.demo.TestContent",bytes,0,length);
    }

    /**
     * 运行主类
     * @param args
     * @throws ClassNotFoundException
     */
    public static void main(String[] args) throws ClassNotFoundException {
        //获取项目路劲
        File file = new File(EncryptionUtils.class.getResource("/").getPath());
        //加解密工具
        EncryptionUtils encryptionUtils = new EncryptionUtils();
        //解析路劲
        encryptionUtils.encryptionClass(file.getPath()+"/com/encryption/demo/TestContent.class");
        //获取解析后的文件
        Class<?> c = encryptionUtils.findClass(parentPath+"/TestContent.classhong");
        if(c != null){
            try {
                Object obj = c.newInstance();
                //获取方法
                Method method = c.getDeclaredMethod("hong");
                //通过反射调用Test类的say方法
                method.invoke(obj);
            } catch (InstantiationException | IllegalAccessException
                    | NoSuchMethodException
                    | SecurityException |
                    IllegalArgumentException |
                    InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

}

结果

Connected to the target VM, address: '127.0.0.1:49636', transport: 'socket'
my name is hong!!!
Disconnected from the target VM, address: '127.0.0.1:49636', transport: 'socket'

Process finished with exit code 0

最后

看过很多实现的方法大同小异,主要是用来学习,以备将来在一些特定场景上面会使用到。当然以上太简单了,如果不懂类加载机制的同学可以参考以往文章。(最近疫情有点反弹,出门注意安全防护。祝各位,一切顺利,未来可期!!!)

参考文章:

https://www.cnblogs.com/peashooter/p/9456402.html

https://blog.csdn.net/qq_28082757/article/details/81481215

https://www.jianshu.com/p/fa127d08e281

文章分享自微信公众号:
技术趋势

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:逍遥壮士
原始发表时间:2022-03-28
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • Java中的屠龙之术(二):如何方便快捷地生成.class文件

    在之前的“Java中的屠龙之术:如何修改语法树”中,我们详细介绍了如何使用Javac源码提供的工具类来修改语法树。

    公众号_程序员黄小斜
  • [Spring Boot] 如何优雅的对配置文件进行加密

    Jasypt Spring Boot为Spring Boot Applications中的属性源提供加密支持。 有三种方法可以集成jasypt-spring-b...

    架构探险之道
  • DES加密ECB模式的Java实现

    一、方案详细说明 更新内容: 报文添加加密功能 使用终端: RTU 加密方式: DES加密 DES加密模式: ECB模式 填充方式: zeropa...

    ccf19881030
  • RSA加密算法的java实现

    实现基本上就是这样,都是大同小异。不过,问题来了,结下来才是重点。 **1. RSA加密算法对于加密数据的长度是有要求的。一般来说,明文长度小于等于密钥长度...

    全栈程序员站长
  • java的rsa加密算法_用java编程实现RSA加密算法

    RSA加密算法是目前应用最广泛的公钥加密算法,特别适用于通过Internet传送的数据,常用于数字签名和密钥交换。那么我今天就给大家介绍一下如何利用Java编程...

    全栈程序员站长
  • Java对阻塞队列的实现ArrayBlockingQueueLinkedBlockingQueue

    怎么实现阻塞呢?可以使用Java中Object类的wait(),notify(),notifyAll()等方法来实现.

    呼延十
  • 实现随机生成汉字的Java代码

    一、背景知识 GB 2312-80 是中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,由中国国家标准总局发布,1981年5月1日实施。GB...

    用户8671053
  • 实现随机生成汉字的Java代码

    GB2312 标准共收录 6763 个汉字,其中一级汉字 3755 个,二级汉字 3008 个;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西...

    用户1503405
  • 【Java 面试题系列 05】Class类的作用是什么?如何获取Class对象?

    Class 类是 Java 反射机制的起源和入口,用于获取与类相关的各种信息,提供了获取类信息的相关方法。

    方才编程_公众号同名
  • Eclipse生成的java class文件通过java命令行调用提示找不到主类的问题

    我相信很多好奇的java初学者在学习时很可能会遇到这个问题:为什么Eclipse编译生成的class文件通过java命令行调用时总出现无法找到主类的问题??

    johnhuster的分享
  • Java 如何手写一段代码实现将java源码编译成字节码? Java文件-》class文件

    核心对象:1 JavaCompiler  2 StandardJavaFilemanager 

    爱明依
  • 如何加强自己对Java的编码规范

    Java,无疑是现在计算机专业最容易找到工作的语言,使用的人也非常多,各大语言排行榜前三一般都会有Java。

    小Bob来啦
  • Java生成十六进制的MD5加密字符串

    joymufeng
  • java的md5加密实现代码

    代码伴一生
  • 如何优雅的实现 Spring Boot 接口参数加密解密?

    松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程

    江南一点雨
  • WhatsApp 是如何实现端到端加密备份的?

    多年以来,WhatsApp 的端对端加密服务一直是默认选项,旨在全力保护人们信息隐私,让信息的交换不经手任何人,仅收件人和发件人可见。现在,WhatsApp 计...

    深度学习与Python
  • 通过JNI实现Java对C/C++的调用

    默认,所有iOS设备在过了设定的休眠时间后,都会自动锁屏。 如果你的应用不希望iOS设备自动锁屏,可以使用以下方式来保持屏幕一直开着。

    EltonZheng
  • 基于JAVA的RSA非对称加密算法简单实现

      RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。

    CodeWwang

扫码关注腾讯云开发者

领取腾讯云代金券