将文件的字节数组加载到内存中

时间:2013-08-24 17:48:50

标签: java memory encryption runtime classloader

我试图将jar文件直接加载到内存中而不将其丢弃到HDD中。我尝试过使用ClassLoader,但是我收到了错误。

这是我的代码:

自定义类加载器

public class CLS_ClassLoader extends ClassLoader {

    private byte[] bArrData;

    public CLS_ClassLoader(ClassLoader parent, byte[] bArrData) {
        super(parent);

        this.bArrData = bArrData;
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return defineClass(name, bArrData, 0,
                bArrData.length);
    }
}

主要

ClassLoader tParentClsLoader = CLS_ClassLoader.class.getClassLoader();
CLS_ClassLoader tClsLoader = new CLS_ClassLoader(tParentClsLoader, fileToByteArray("D:/App.jar"));
Class<?> tClass = null;

try {
        tClass = tClsLoader.loadClass("pkg_main.CLS_Main");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

输出

Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1347093252 in class file pkg_main/CLS_Main
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at pkg_main.CLS_ClassLoader.loadClass(CLS_ClassLoader.java:20)
    at pkg_main.CSL_Main.main(CSL_Main.java:27)

我的想法是获取一个加密的jar文件,在运行时解密并直接加载到内存中。

抱歉打字错误,我说英语不好。提前谢谢!

1 个答案:

答案 0 :(得分:3)

你的主要错误是defineClass(...)期望类字节而你正在用整个jar文件提供它。如果类字节不以0xCAFEBABE(典型的Java类文件头)开头,则抛出实际异常。因此,您需要一个额外的步骤来对jar文件中的类进行排序。以下实现演示了这个想法:

 class CCLoader extends ClassLoader {
    private Map<String, byte[]> classes = new HashMap<String, byte[]>();

    public CCLoader(InputStream in) {
        super(CCLoader.class.getClassLoader());
        try {
            JarInputStream jis = new JarInputStream(in);
            JarEntry je = null;
            String entryName = null;
            while ((je = jis.getNextJarEntry()) != null) {
                entryName = je.getName();
                if (je.getName().endsWith(".class")) {
                    byte[] classBytes = readClass(jis);
                    String canonicalName = entryName.replaceAll("/", ".").replaceAll(".class", "");
                    classes.put(canonicalName, classBytes);
                }
            }
            jis.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private byte[] readClass(InputStream stream) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while(true){
            int qwe = stream.read();
            if(qwe == -1) break;
            baos.write(qwe);
        }
        return baos.toByteArray();
    }

    public Class loadClass(String name) throws ClassNotFoundException {
        try {
            return this.getParent().loadClass(name);
        } catch (ClassNotFoundException e) {
            return findClass(name);
        }
    }

    public Class findClass(String name) throws ClassNotFoundException {
        byte[] classBytes = classes.get(name);
        return defineClass(name, classBytes, 0, classBytes.length);
    }

}

按照你的例子你可以这样尝试:

ClassLoader tClsLoader = new CCLoader(new FileInputStream("C:/commons-io-2.0.1.jar"));
Class<?> tClass = tClsLoader.loadClass("org.apache.commons.io.FileExistsException");