天天看点

自定义ClassLoader进行class文件加密

作者:MYJ2C混淆

1.基础使用ClassLoader

1.1 创建自定义ClassLoader并继承ClassLoader

这里我只覆写了一个findClass方法(实际上可以覆写更多方法)因为在下文我需要达到加密class,需要覆写该findClass(),在该findClass里,调用了我自己写的一个method:getClassByte(),该方法的作用是读取class文件字节流,那么我们的加密手段,可以在该方法中做文章哈。当classData为空的时候,我们就交给super的方法处理(抛出ClassNotFound的异常),当classData不为空,那么我们就加载该类。

import java.io.*;

public class MyClassLoader extends ClassLoader {
    private String classPath;
    private final static int BUFSIZE = 4096;

    public MyClassLoader(String classPath){
        this.classPath = classPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException{
       try{
           byte[] classData = getClassByte(name);
           if(classData!=null){
               return defineClass(name,classData,0,classData.length);
           }
       }catch (IOException e){
           e.printStackTrace();
       }
       return super.findClass(name);
    }

    /***
     * class字节流获取
     */
    private byte[] getClassByte(String className) throws IOException{
        String classRealPath = classPath + File.separatorChar + className.replace('.',File.separatorChar)+".class";
        byte[] buf = new byte[BUFSIZE];
        int len;
        ByteArrayOutputStream out = null;
        try(InputStream in = new FileInputStream(classRealPath);){
            out = new ByteArrayOutputStream();
            while ((len = in.read(buf))!=-1){
                out.write(buf,0,len);
            }
        }catch (FileNotFoundException ex){
            ex.printStackTrace();
        }finally {
            if(out!=null){
                out.close();
            }

        }
        if(out!=null){
            return out.toByteArray();
        }
        return null;
    }

}           

2.ClassLoader测试

测试主类中,使用该类加载器进行加载我已经预先编译好的class文件,该文件不要存在运行项目之下,会导致系统加载器加载该文件,测试主类:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyClassLoaderTest {
    public static void main(String []args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        //自定义类加载器的加载路径
        MyClassLoader myClassLoader=new MyClassLoader("C:\\testcl");
        //包名+类名
        Class c=myClassLoader.loadClass("MyClassLoaderTestClass");

        if(c!=null){
            Object obj=c.newInstance();
            Method method=c.getMethod("test", null);
            method.invoke(obj, null);
            System.out.println(c.getClassLoader().toString());
        }
    }
}           

可以看出MyClassLoader已经生效了,运行结果如下:

This is success
classload.MyClassLoader@12bb4df8           

3. ClassLoader改造Secuity ClassLoader

3.1 加密解密类

这里只编写单字节的加密,所以一次读取一个字节,而后异或一个数作为加密。

import java.io.*;

public class EncrypClassFile {
    public static void encrypt(String src, String dest) throws IOException {
        try(InputStream in = new FileInputStream(src);
            OutputStream out = new FileOutputStream(dest);) {
            int c = -1;
            while ((c = in.read()) != -1) {
                // 进行单字节加密
                out.write(encryptAlgorithm(c));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /***
     * 单字节加密算法
     */
    public static int encryptAlgorithm(int c){
        return c ^ 0xff;
    }

    /***
     * 单字节解密算法
     */
    public static int decryptAlgorithm(int c){
        return c ^ 0xff;
    }

    public static void main(String[] args) throws IOException {
        encrypt("C:\\testcl\\MyClassLoaderTestClass.class"
        ,"C:\\testcl\\MyClassLoaderTestClass.eclass");
    }
}           

3.2 ClassLoader类改造

主要改造的是:getClassByte(),从每次获取BUFSIZE大小的数组变成每次获取单字节,而后进行解密,拼接的文件后缀,由于加密文件为eclass,所以这里也需要变成eclass。

import java.io.*;

public class MyClassLoader extends ClassLoader {
    private String classPath;
    private final static int BUFSIZE = 4096;

    public MyClassLoader(String classPath){
        this.classPath = classPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException{
       try{
           byte[] classData = getClassByte(name);
           if(classData!=null){
               return defineClass(name,classData,0,classData.length);
           }
       }catch (IOException e){
           e.printStackTrace();
       }
       return super.findClass(name);
    }

    /***
     * class字节流获取
     */
    private byte[] getClassByte(String className) throws IOException{
        String classRealPath = classPath + File.separatorChar + className.replace('.',File.separatorChar)+".eclass";
        byte[] buf = new byte[BUFSIZE];
        int c;
        ByteArrayOutputStream out = null;
        try(InputStream in = new FileInputStream(classRealPath);){
            out = new ByteArrayOutputStream();
            while ((c = in.read())!=-1){
                out.write(EncrypClassFile.decryptAlgorithm(c));
            }
        }catch (FileNotFoundException ex){
            ex.printStackTrace();
        }finally {
            if(out!=null){
                out.close();
            }

        }
        if(out!=null){
            return out.toByteArray();
        }
        return null;
    }

}           

3.3 测试效果

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyClassLoaderTest {
    public static void main(String []args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        //自定义类加载器的加载路径
        MyClassLoader myClassLoader=new MyClassLoader("C:\\testcl");
        //包名+类名
        Class c=myClassLoader.loadClass("MyClassLoaderTestClass");

        if(c!=null){
            Object obj=c.newInstance();
            Method method=c.getMethod("test", null);
            method.invoke(obj, null);
            System.out.println(c.getClassLoader().toString());
        }
    }
}           

运行结果:

This is success
classload.MyClassLoader@12bb4df8           

继续阅读