如何将bytearray转换为Jar

我正在尝试从字节数组加载jar而不将其写入文件(将其加载到内存中)。 我已经创建了一个自定义的ClassLoader,但是当我尝试使用它并加载一个类时,它给了我ClassNotFoundException。

类加载器

public class NetworkClassLoader extends ClassLoader { /* * Default ClassLoader. */ private final ClassLoader startup; /* * Byte array used to load classes. */ private final byte[] bytes; /* * HashMap used to contain cached classes. */ private HashMap classes = new HashMap(); /* * Initializes byte array used for loading classes. * @param ClassLoader classLoader * @param byte[] bytes */ public NetworkClassLoader(ClassLoader classLoader, byte[] bytes) { this.startup = classLoader; this.bytes = bytes; } /* * Loads class from name. * (non-Javadoc) * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean) * @param String name * @param boolean resolve * @throws ClassNotFoundException * @returns clazz */ @Override public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class clazz = findLoadedClass(name); if (clazz == null) { try { InputStream in = getResourceAsStream(name.replace('.', '/') + ".class"); if (in == null) return null; ByteArrayOutputStream out = new ByteArrayOutputStream(); IOUtils.writeStream(in, out); in.close(); byte[] bytes = out.toByteArray(); out.close(); clazz = defineClass(name, bytes, 0, bytes.length); if (resolve) { resolveClass(clazz); } } catch (Exception e) { clazz = super.loadClass(name, resolve); } } return clazz; } /* * Returns resource. * (non-Javadoc) * @see java.lang.ClassLoader#getResource(java.lang.String) * @param String name */ @Override public URL getResource(String name) { return null; } /* * Returns resource as stream. * (non-Javadoc) * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String) * @param String name * @return ByteArrayInputStream */ @Override public InputStream getResourceAsStream(String name) { InputStream jarRes = this.startup.getResourceAsStream(name); if (jarRes != null) { return jarRes; } if (!this.classes.containsKey(name)) { return null; } return new ByteArrayInputStream((byte[])this.classes.get(name)); } /* * Loads classes using byte array. */ public void inject() { if (bytes == null) return; try { JarInputStream jis = new JarInputStream(new ByteArrayInputStream(bytes)); try { JarEntry entry; while ((entry = jis.getNextJarEntry()) != null) { String entryName = entry.getName(); ByteArrayOutputStream out = new ByteArrayOutputStream(); IOUtils.writeStream(jis, out); byte[] bytes = out.toByteArray(); this.classes.put(entryName, bytes); this.loadClass(entryName, false); } } catch (Exception e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } } } 

主要

 byte[] array = IOUtils.readFileBytes(new File("C:\\Users\\o_m_a\\Desktop\\HWID.jar")); ByteClassLoader loader = new ByteClassLoader(Main.class.getClassLoader(), array); loader.inject(); //System.out.println(Arrays.toString(array)); try { Class clazz = loader.loadClass("Main", true).newInstance(); Method m = clazz.getMethod(method, (Class[]) null); m.setAccessible(true); m.invoke(clazz.newInstance(), (Object[]) null); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } 

它正确加载我的类并运行它,但我不断得到随机错误。

这有点hackish但做他的工作,这个代码基本上创建了一个假的url方案(myjarprotocol),当打开时返回jarBytes字段(你的真正的jar数据去的地方)。 然后通过reflection调用SystemClassLoader.addURL ,它将URL作为他必须加载的jar的参数。 总而言之,SystemClassLoader被欺骗从伪url方案加载jar,返回任何你想要的InputStream。

 public class JarLoader { private static final byte[] jarBytes = new byte[] { 0x00 /* .... etc*/ }; public static void main(String[] args) throws Exception { URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() { public URLStreamHandler createURLStreamHandler(String urlProtocol) { System.out.println("Someone asked for protocol: " + urlProtocol); if ("myjarprotocol".equalsIgnoreCase(urlProtocol)) { return new URLStreamHandler() { @Override protected URLConnection openConnection(URL url) throws IOException { return new URLConnection(url) { public void connect() throws IOException {} public InputStream getInputStream() throws IOException { System.out.println("Someone is getting my jar!!"); return new ByteArrayInputStream(jarBytes); } }; } }; } return null; } }); System.out.println("Loading jar with fake protocol!"); loadJarFromURL(new URL("myjarprotocol:fakeparameter")); } public static final void loadJarFromURL(URL jarURL) throws Exception { URLClassLoader systemClassloader = (URLClassLoader) ClassLoader.getSystemClassLoader(); Method systemClassloaderMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); systemClassloaderMethod.setAccessible(true); systemClassloaderMethod.invoke(systemClassloader, jarURL); // This make classloader open the connection systemClassloader.findResource("/resource-404"); } } 

在做了一些研究之后,看起来你实际上正在使用错误的库。

而不是IOUtils.copyStream(in, out); 尝试使用StreamUtils.writeTo(in, out);