当前位置: 首页 > 面试题库 >

如何将字节数组转换为Jar

汪凌
2023-03-14
问题内容

我正在尝试从字节数组加载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<String, byte[]> 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();
    }

它可以正确加载我的课程并运行它,但是我一直在遇到随机错误。


问题答案:

这有点骇人听闻,但是他做了他的工作,这段代码基本上创建了一个伪造的url方案(myjarprotocol),当打开该方案时,它会返回该jarBytes字段(您的实际jar数据所在的位置)。然后通过反射它调用SystemClassLoader.addURL以URL作为他必须加载的jar参数。总之,SystemClassLoader被欺骗从伪造的url方案加载jar,该url方案返回您想要的任何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");
    }

}


 类似资料:
  • 问题内容: 我想从数据库中获取图像。为此,我为图像创建了一个字节数组,该数组由字符串传递,现在我想将该字符串转换为图像格式。我正在将该图像分配给Jlabel字段。代码如下: 问题答案:

  • 有什么方法可以将byte[]转换为org.springframework.web.multipart.multipartfile??

  • 问题内容: 我正在使用以下方式读取文件: 我在这里发现。可以转换为吗?将转换为会占用更多空间吗? 编辑:我的文件包含数百万个整数,例如, 100000000 200000000 .....(使用普通的int文件写入)。我读到字节缓冲区。现在,我想将其包装到IntBuffer数组中。怎么做 ?我不想将每个字节转换为int。 问题答案: 您已经在注释中说过,您希望输入数组中的四个字节对应于输出数组中的

  • 我得到一个错误读数:

  • 问题内容: 使用Javascript,我正在对WCF服务进行AJAX调用,并且正在返回字节数组。如何将其转换为图像并显示在网页上? 问题答案: 我意识到这是一个旧线程,但是我设法通过Web服务上的AJAX调用做到了这一点,并认为我愿意分享… 我的页面中已经有图像: AJAX: 我的“ GetItemPreview”代码查询一个SQL Server,其中我将图像存储为base64字符串,并将该字段作

  • 我必须在皈依前向小恩迪安下订单。 在第一种情况下,我很容易进行转换: 在第二种情况下,转换不起作用: 数字3832745171大于,但如果我试图转换为long,我也会遇到问题。 我怎么能这么做?谢谢。 尝试将字节数组转换为int/long类型。