A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 上海分校-小影 于 2018-6-1 17:14 编辑

类加载器加密class文件

需求介绍:Java本身是开源的技术,那么只要拥有反编译工具和项目的.class文件就可以获取源代码内容。
那么如何在源代码级别增强安全性呢?
答:对.class文件做加密操作,让反编译工具无法反编译.class文件
那么如何开始做这个加密操作呢?
答:修改.class文件底层的字节数据
代码演示:
/**
     * @throws Exception
     * 对Class文件进行加密
     */
    @Test
    public void test1() throws Exception {
        FileInputStream in = new FileInputStream(new File("d:/class/MD5Utils.class"));

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buf = new byte[2048];
        int len = 0;
        byte mi = 1;
        while ((len = in.read(buf)) != -1) {
            for (int i = 0; i < buf.length; i++) {
                System.out.println("第一次:" + buf);
                buf = (byte) (buf + mi);
                System.out.println("第二次:" + buf);
            }
            out.write(buf, 0, len);
        }
        byte[] byteArray = out.toByteArray();

        FileOutputStream fout = new FileOutputStream(new File("d:/clazz/MD5Utils.class"));

        fout.write(byteArray, 0, byteArray.length);
    }
那么加密完成之后这个文件如何运行呢?
答:使用类加载器,读取加载文件,创建类对象,调用方法

package cn.itcast.loader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class MyClassLoader extends ClassLoader{

    @Override
    public Class findClass(String name)  {
        
        //自定义一个类加载器:加载指定位置的.class文件(d:/class)
        String path = "d:/clazz";
        try {
            FileInputStream in = new FileInputStream(new File(path+"/"+name+".class"));
            //根据获取到的数据,创建Class对象
            //需要一个将数据转换为字节数组的输出流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            
            int len = 0;
            byte[] buf = new byte[1024];
            while((len = in.read(buf)) != -1){
               
                out.write(buf, 0, len);
            }
            byte[] byteArray = out.toByteArray();
            for (int i = 0; i < byteArray.length; i++) {
                byteArray = (byte) (byteArray - 1);
            }
            
            return defineClass(name, byteArray, 0, byteArray.length);
            
        } catch (Exception e) {
            e.printStackTrace();
            try {
                return super.findClass(name);
            } catch (ClassNotFoundException e1) {
                e1.printStackTrace();
                return null;
            }
        }
    }
}
在加密的转换过程中byte数据底层加减可能出现超出数据范围的情况(例如:127+1),但是,我们的转换过程中,没有出现任何问题,这是为什么呢?
接下来我们一点点来分析下:

/**
     * 问题:加密 加多少,解密,减多少——————》加密前是多少,加密后,数字也是多少?目前的效果,也是对的
     *
     * 问题:加法运算可能超出byte类型数据的范围,会导致加密解密失败,但是这里为什么没有失败?
     * 同学们的思路:
     *
     *    -127  1111 1111
     *  +   1   0000 0001
     *  ---------------------
     *         10000 0000
     * 最高丢弃       0000 0000 ————》  0
     *
     *      0   0000 0000
     *  -   1   0000 0001
     *  ------------------
     *     -1   1000 0001
     *     
     * 问题:数据经过加减之后,尽然可以,保持原样,那么计算底层到底是怎么计算的?
     *
     * 1 计算底层,所有都是加法运算
     *
     *      1 0000 0001
     *  -   1 0000 0001
     *  ----------------
     *  所有减法都是加法
     *  
     *      1 0000 0001
     *  +  -1 1000 0001
     *  -----------------
     *     -2 1000 0010
     * 错误的结果————按照普通人类的思路
     *
     * 按照机器思路做减法:
     *
     *      1 0000 0001
     *  +  -1 1000 0001
     *  -----------------
     *  获取当前数据(-1)的反码:0 ————》1  1————》0,最高位不动
     *  
     *      1 0000 0001
     *  +  -1 1111 1110
     *  -----------------
     *        1111 1111
     *  在反码计算结果的基础上加一(补码):
     *        1111 1111
     *  +   1 0000 0001
     *  ----------------
     *       10000 0000
     * byte数据最高位去掉:
     *        0000 0000 ——————》 0
     *
     * 按照机器思路进行加密和解密
     *    -127  1111 1111
     *  +   1   0000 0001
     *  ---------------------
     *         10000 0000
     * byte数据最高位去掉:
     *          0000 0000 ——————》 0
     * 以上是加密
     *
     * 以下解密:
     *          0000 0000
     *    +     1000 0001
     *    ----------------
     *   
     *  反码:  
     *          0000 0000
     *    +     1111 1110
     *    ----------------
     *          1111 1110
     *     
     *  补码:
     *          1111 1110
     *    +     0000 0001
     *  -------------------
     *          1111 1111
     *         
     * 总结:加密和解密不会导致,数据前后不一致,是因为,二进制减法计算的是使用了反码和补码的方式。
     * */
通过以上分析,我们发现其实在计算的过程中,计算机使用的是二进制的补码和反码进行运算,因此,没有数据超出范围的问题。

1 个回复

倒序浏览
我来占层楼啊   
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马