天天看點

自定義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           

繼續閱讀