java自定义类加载器与实现类加载器加密与解密

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40646143/article/details/84997331

创建自定义加载器的类

package com.tuogo.classlocad;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 自定义类加载器
 */
public class EncryptionClass extends ClassLoader {

    private String srcFile;

    public EncryptionClass(String srcFile) {
        this.srcFile = srcFile;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        Class<?> loadedClass = findLoadedClass(name);
        if (null != loadedClass) {
            return loadedClass;
        } else {
            //采用双亲委托机制 这里使用异常如果出错则继续向下执行
            try {
                loadedClass = this.getParent().loadClass(name);
            } catch (Exception e) {

            }
            if (loadedClass != null) {
                return loadedClass;
            } else {
                byte[] bytes = getClassDate(name);
                if (bytes == null) {
                    throw new ClassNotFoundException();
                }
                loadedClass = defineClass(name, bytes, 0, bytes.length);
            }

        }
        return loadedClass;
    }

    private byte[] getClassDate(String name) {

        //获取class的全路径
        String file = srcFile + "/" + name.replace(".", "/") + ".class";

        ByteArrayOutputStream outputStream = null;
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            outputStream = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int tmp = 0;
            while ((tmp = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, tmp);
            }
            return outputStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }


            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在测试类加载器之前 我的本地已经创建好了class文件

使用文件创建一个.java的后缀文件 ,然后利用cmd编把.java文件编译成.class文件,接下来在进行测试

测试类加载器

package com.tuogo.classlocad;

/**
 *测试类加载器
 * 同一类加载加载同一class文件 hashcode会相同     如hello1  hello2
 * 同一个类 由不同的类加载器加载  hashcoode不相同  如hello1  hello3
 */
public class EncryptionDemo {
    public static void main (String[] args) {
        EncryptionClass encryptionClass1 = new EncryptionClass("E:/java");
        EncryptionClass encryptionClass2= new EncryptionClass("E:/java");

        try {

            Class<?> hello1 = encryptionClass1.loadClass("Hello");
            Class<?> hello2 = encryptionClass1.loadClass("Hello");
            Class<?> hello3 = encryptionClass2.loadClass("Hello");
            System.out.println(hello1.hashCode());
            System.out.println(hello2.hashCode());
            System.out.println(hello3.hashCode());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

效果如下

类的加密与解密方式

加密class类的类

package com.tuogo.classlocad;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 这个类实现了类的加密
 */
public class Encryption {

    public static void main (String[] args) {
        try {
            encrypt("E:/java/Hello.class","E:/java/tmp/Hello.class");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void encrypt(String src, String dest) throws IOException {

        FileInputStream fis = null;
        FileOutputStream fos = null;


        try {
            fis = new FileInputStream(src);
            fos = new FileOutputStream(dest);
            int tmp = -1;
            while ((tmp = fis.read()) != -1) {
                //^0xff  取反操作
                fos.write(tmp^0xff);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                fis.close();
            }

            if (fos != null) {
                fos.close();
            }
        }
    }
}

执行成功在本地的tmp包下创建一个加密后的.class文件,如下

如果直接使用类加载其进行加载,则会出现以下异常

Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 889275713 in class file Hello
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
	at com.tuogo.classlocad.EncryptionClass.loadClass(EncryptionClass.java:37)
	at com.tuogo.classlocad.EncryptionDemo.main(EncryptionDemo.java:14)

接下来我们对class类进行解密这样才能最正确的获取class类的二进制数据

改动如下

package com.tuogo.classlocad;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 自定义类加载器
 */
public class EncryptionClass extends ClassLoader {

    private String srcFile;

    public EncryptionClass(String srcFile) {
        this.srcFile = srcFile;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        Class<?> loadedClass = findLoadedClass(name);
        if (null != loadedClass) {
            return loadedClass;
        } else {
            //采用双亲委托机制 这里使用异常如果出错则继续向下执行
            try {
                loadedClass = this.getParent().loadClass(name);
            } catch (Exception e) {

            }
            if (loadedClass != null) {
                return loadedClass;
            } else {
                byte[] bytes = getClassDate(name);
                if (bytes == null) {
                    throw new ClassNotFoundException();
                }
                loadedClass = defineClass(name, bytes, 0, bytes.length);
            }

        }
        return loadedClass;
    }

    private byte[] getClassDate(String name) {

        //获取class的全路径
        String file = srcFile + "/" + name.replace(".", "/") + ".class";

        ByteArrayOutputStream outputStream = null;
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            outputStream = new ByteArrayOutputStream();
            int tmp = -1;
            while ((tmp = inputStream.read()) != -1) {
                //^0xff  取反操作
                outputStream.write(tmp^0xff);
            }
            return outputStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }


            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

测试解密

package com.tuogo.classlocad;

/**
 *测试类加载器 解密
 */
public class EncryptionDemo {
    public static void main (String[] args) {
        EncryptionClass encryptionClass1 = new EncryptionClass("E:/java/tmp");

        try {
    //加载  加密后的class文件会出现 java.lang.ClassFormatError: Incompatible magic value 889275713 in class file Hello错误信息
            Class<?> hello1 = encryptionClass1.loadClass("Hello");
            System.out.println(hello1.hashCode());

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

运行结果

总结 :  类的加密与解密 需要统一方式 不能加密使用一种方式解密使用另一种方式

 加密与解密用的是^0xff 取反

比如 int 3;  按一个字节来算的话是 00000011 (3的二进制表示形式)

0 0 0 0 0 0 1 1  3 的二进制
1 1 1 1 1 1 1 1  ff取反的意思
----------------
1 1 1 1 1 1 0 0   结果

猜你喜欢

转载自blog.csdn.net/qq_40646143/article/details/84997331