运行 内存中有文件的 jar 文件
Run jar file with file in memory
我创建了一个加密和解密 jar 文件的应用程序。我希望此应用程序解密文件,而不必将文件写入磁盘,运行 应用程序。有可能吗?
我用 C# 创建了这个应用程序,但它也可以用其他语言创建。
概念验证,主要归功于this overflower. You will need this class到运行它。当然,您的数组不是来自嵌入的 Base64 字符串,而是来自解密的 byte[]
。 JARENC
是一个jar文件:
package com.technojeeves.shm;
import com.technojeeves.io.IOUtils;
import java.util.Base64;
import java.util.zip.*;
import java.util.*;
import java.io.*;
import java.lang.reflect.Method;
public class Loader {
public static void main(String[] args) {
final String JARENC = "UEsDBBQACAgIABqp8FIAAAAAAAAAAAAAAAAlAAQAY29tL3RlY2hub2plZXZlcy9zaG0vSGVsbG9Xb3JsZC5jbGFzc/7KAABtUMtOwkAUPZdXaa2CIPgkwsIEXNiNO4wbE+OCqAkGF65KmcCQtmPKgPGzdKGJCz/AjzLeaUzQhFncx5nzSO7X98cngFM0HGSQtZBzkUeBUJ76C98L/Xjs3QynItCEwpmMpT4nZNudgY0ibAuOizW4/+j955kWEbPUnEW1XvojlXebyFj3dSL8qFvEBsG9EmGomk8qCUctB2VsWqi4qGKLUF2hIliPZgtjtm33/iRqhsfdzsBCnXAYqMjTIpjEairEQsy82STy0qx7E0XIXaiRIJR6MhbX82gokjt/GDKSi3zJ5vX2wyp3gtNX8yQQl9KQS0vLE8NGCzW+oXkZkLki123eGtyJe/74HfTCA2GHayEFs7Cxi71f6lEqBexXWJX1N5SWdCf1zvPZjXA/TTn4AVBLBwhqV5QAMQEAAL8BAABQSwECFAAUAAgICAAaqfBSaleUADEBAAC/AQAAJQAEAAAAAAAAAAAAAAAAAAAAY29tL3RlY2hub2plZXZlcy9zaG0vSGVsbG9Xb3JsZC5jbGFzc/7KAABQSwUGAAAAAAEAAQBXAAAAiAEAAAAA";
try {
Base64.Decoder dec = Base64.getDecoder();
byte[] jarBytes = dec.decode(JARENC);
RemoteClassLoader memJarLoader = new RemoteClassLoader(jarBytes);
Class<?> hw = memJarLoader.loadClass("com.technojeeves.shm.HelloWorld", true);
Method main = hw.getMethod("main", String[].class);
String[] params = null;
main.invoke(null, (Object)params);
} catch (Throwable t) {
t.printStackTrace();
}
}
static class RemoteClassLoader extends ClassLoader {
private final byte[] jarBytes;
private final Set<String> names;
public RemoteClassLoader(byte[] jarBytes) throws IOException {
this.jarBytes = jarBytes;
this.names = RemoteClassLoader.loadNames(jarBytes);
}
/**
* This will put all the entries into a thread-safe Set
*/
private static Set<String> loadNames(byte[] jarBytes) throws IOException {
Set<String> set = new HashSet<>();
try (ZipInputStream jis = new ZipInputStream(new ByteArrayInputStream(jarBytes))) {
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
set.add(entry.getName());
}
}
return Collections.unmodifiableSet(set);
}
@Override
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(name);
if (clazz == null) {
try {
String toLoad = name.replace('.', '/') + ".class";
//System.out.printf("Attempting to load %s%n", toLoad);
InputStream in = getResourceAsStream(name.replace('.', '/') + ".class");
ByteArrayOutputStream out = new ByteArrayOutputStream();
//StreamUtils.writeTo(in, out);
IOUtils.copyStream(in, out);
byte[] bytes = out.toByteArray();
clazz = defineClass(name, bytes, 0, bytes.length);
if (resolve) {
resolveClass(clazz);
}
} catch (Exception e) {
clazz = super.loadClass(name, resolve);
}
}
return clazz;
}
@Override
public InputStream getResourceAsStream(String name) {
// Check first if the entry name is known
if (!names.contains(name)) {
return null;
}
// I moved the JarInputStream declaration outside the
// try-with-resources statement as it must not be closed otherwise
// the returned InputStream won't be readable as already closed
boolean found = false;
ZipInputStream jis = null;
try {
jis = new ZipInputStream(new ByteArrayInputStream(jarBytes));
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
if (entry.getName().equals(name)) {
found = true;
return jis;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// Only close the stream if the entry could not be found
if (jis != null && !found) {
try {
jis.close();
} catch (IOException e) {
// ignore me
}
}
}
return null;
}
}
}
我创建了一个加密和解密 jar 文件的应用程序。我希望此应用程序解密文件,而不必将文件写入磁盘,运行 应用程序。有可能吗?
我用 C# 创建了这个应用程序,但它也可以用其他语言创建。
概念验证,主要归功于this overflower. You will need this class到运行它。当然,您的数组不是来自嵌入的 Base64 字符串,而是来自解密的 byte[]
。 JARENC
是一个jar文件:
package com.technojeeves.shm;
import com.technojeeves.io.IOUtils;
import java.util.Base64;
import java.util.zip.*;
import java.util.*;
import java.io.*;
import java.lang.reflect.Method;
public class Loader {
public static void main(String[] args) {
final String JARENC = "UEsDBBQACAgIABqp8FIAAAAAAAAAAAAAAAAlAAQAY29tL3RlY2hub2plZXZlcy9zaG0vSGVsbG9Xb3JsZC5jbGFzc/7KAABtUMtOwkAUPZdXaa2CIPgkwsIEXNiNO4wbE+OCqAkGF65KmcCQtmPKgPGzdKGJCz/AjzLeaUzQhFncx5nzSO7X98cngFM0HGSQtZBzkUeBUJ76C98L/Xjs3QynItCEwpmMpT4nZNudgY0ibAuOizW4/+j955kWEbPUnEW1XvojlXebyFj3dSL8qFvEBsG9EmGomk8qCUctB2VsWqi4qGKLUF2hIliPZgtjtm33/iRqhsfdzsBCnXAYqMjTIpjEairEQsy82STy0qx7E0XIXaiRIJR6MhbX82gokjt/GDKSi3zJ5vX2wyp3gtNX8yQQl9KQS0vLE8NGCzW+oXkZkLki123eGtyJe/74HfTCA2GHayEFs7Cxi71f6lEqBexXWJX1N5SWdCf1zvPZjXA/TTn4AVBLBwhqV5QAMQEAAL8BAABQSwECFAAUAAgICAAaqfBSaleUADEBAAC/AQAAJQAEAAAAAAAAAAAAAAAAAAAAY29tL3RlY2hub2plZXZlcy9zaG0vSGVsbG9Xb3JsZC5jbGFzc/7KAABQSwUGAAAAAAEAAQBXAAAAiAEAAAAA";
try {
Base64.Decoder dec = Base64.getDecoder();
byte[] jarBytes = dec.decode(JARENC);
RemoteClassLoader memJarLoader = new RemoteClassLoader(jarBytes);
Class<?> hw = memJarLoader.loadClass("com.technojeeves.shm.HelloWorld", true);
Method main = hw.getMethod("main", String[].class);
String[] params = null;
main.invoke(null, (Object)params);
} catch (Throwable t) {
t.printStackTrace();
}
}
static class RemoteClassLoader extends ClassLoader {
private final byte[] jarBytes;
private final Set<String> names;
public RemoteClassLoader(byte[] jarBytes) throws IOException {
this.jarBytes = jarBytes;
this.names = RemoteClassLoader.loadNames(jarBytes);
}
/**
* This will put all the entries into a thread-safe Set
*/
private static Set<String> loadNames(byte[] jarBytes) throws IOException {
Set<String> set = new HashSet<>();
try (ZipInputStream jis = new ZipInputStream(new ByteArrayInputStream(jarBytes))) {
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
set.add(entry.getName());
}
}
return Collections.unmodifiableSet(set);
}
@Override
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(name);
if (clazz == null) {
try {
String toLoad = name.replace('.', '/') + ".class";
//System.out.printf("Attempting to load %s%n", toLoad);
InputStream in = getResourceAsStream(name.replace('.', '/') + ".class");
ByteArrayOutputStream out = new ByteArrayOutputStream();
//StreamUtils.writeTo(in, out);
IOUtils.copyStream(in, out);
byte[] bytes = out.toByteArray();
clazz = defineClass(name, bytes, 0, bytes.length);
if (resolve) {
resolveClass(clazz);
}
} catch (Exception e) {
clazz = super.loadClass(name, resolve);
}
}
return clazz;
}
@Override
public InputStream getResourceAsStream(String name) {
// Check first if the entry name is known
if (!names.contains(name)) {
return null;
}
// I moved the JarInputStream declaration outside the
// try-with-resources statement as it must not be closed otherwise
// the returned InputStream won't be readable as already closed
boolean found = false;
ZipInputStream jis = null;
try {
jis = new ZipInputStream(new ByteArrayInputStream(jarBytes));
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
if (entry.getName().equals(name)) {
found = true;
return jis;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// Only close the stream if the entry could not be found
if (jis != null && !found) {
try {
jis.close();
} catch (IOException e) {
// ignore me
}
}
}
return null;
}
}
}