Skip to content

Instantly share code, notes, and snippets.

@ZekerZhayard
Created July 11, 2021 16:27
Show Gist options
  • Save ZekerZhayard/aa015e63a068b6ab7b0d610942527a75 to your computer and use it in GitHub Desktop.
Save ZekerZhayard/aa015e63a068b6ab7b0d610942527a75 to your computer and use it in GitHub Desktop.
HOLLY SHIT
package io.github.zekerzhayard.wrappertest;
import java.io.File;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.lang.module.ResolvedModule;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import sun.misc.Unsafe;
public class Wrapper {
private static List<String> moduleList = List.of("asm-", "bootstraplauncher-", "securejarhandler-");
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Throwable {
// Get theUnsafe
var unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
var unsafe = (Unsafe) unsafeField.get(null);
// Get IMPL_LOOKUP
var implLookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
var implLookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(implLookupField), unsafe.staticFieldOffset(implLookupField));
// Define "legacyClassPath"
System.setProperty("legacyClassPath", System.getProperty("java.class.path"));
// Find all extra modules
var finder = ModuleFinder.of(Arrays.stream(System.getProperty("java.class.path").split(File.pathSeparator)).map(Paths::get).filter(p -> moduleList.stream().anyMatch(s -> p.getFileName().toString().startsWith(s))).toArray(Path[]::new));
var loadModuleMH = implLookup.findVirtual(Class.forName("jdk.internal.loader.BuiltinClassLoader"), "loadModule", MethodType.methodType(void.class, ModuleReference.class));
// Resolve modules to a new config
var config = Configuration.resolveAndBind(finder, List.of(ModuleLayer.boot().configuration()), finder, finder.findAll().stream().peek(mref -> {
try {
// Load all extra modules in system class loader (unnamed modules for now)
loadModuleMH.invokeWithArguments(ClassLoader.getSystemClassLoader(), mref);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}).map(ModuleReference::descriptor).map(ModuleDescriptor::name).collect(Collectors.toList()));
// Copy the new config graph to boot module layer config
var graphGetter = implLookup.findGetter(Configuration.class, "graph", Map.class);
var graphMap = new HashMap<>((Map<ResolvedModule, Set<ResolvedModule>>) graphGetter.invokeWithArguments(config));
var cfSetter = implLookup.findSetter(ResolvedModule.class, "cf", Configuration.class);
// Reset all extra resolved modules config to boot module layer config
graphMap.forEach((k, v) -> {
try {
cfSetter.invokeWithArguments(k, ModuleLayer.boot().configuration());
v.forEach(m -> {
try {
cfSetter.invokeWithArguments(m, ModuleLayer.boot().configuration());
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
});
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
});
graphMap.putAll((Map<ResolvedModule, Set<ResolvedModule>>) graphGetter.invokeWithArguments(ModuleLayer.boot().configuration()));
implLookup.findSetter(Configuration.class, "graph", Map.class).invokeWithArguments(ModuleLayer.boot().configuration(), Map.copyOf(graphMap));
// Reset boot module layer resolved modules as new config resolved modules to prepare define modules
var oldBootModules = ModuleLayer.boot().configuration().modules();
var modulesSetter = implLookup.findSetter(Configuration.class, "modules", Set.class);
var modulesSet = new HashSet<>(config.modules());
modulesSetter.invokeWithArguments(ModuleLayer.boot().configuration(), Set.copyOf(modulesSet));
// Prepare to add all of the new config "nameToModule" to boot module layer config
var nameToModuleGetter = implLookup.findGetter(Configuration.class, "nameToModule", Map.class);
var nameToModuleMap = new HashMap<>((Map<String, ResolvedModule>) nameToModuleGetter.invokeWithArguments(ModuleLayer.boot().configuration()));
nameToModuleMap.putAll((Map<String, ResolvedModule>) nameToModuleGetter.invokeWithArguments(config));
implLookup.findSetter(Configuration.class, "nameToModule", Map.class).invokeWithArguments(ModuleLayer.boot().configuration(), Map.copyOf(nameToModuleMap));
// Define all extra modules and add all of the new config "nameToModule" to boot module layer config
((Map<String, Module>) implLookup.findGetter(ModuleLayer.class, "nameToModule", Map.class).invokeWithArguments(ModuleLayer.boot())).putAll((Map<String, Module>) implLookup.findStatic(Module.class, "defineModules", MethodType.methodType(Map.class, Configuration.class, Function.class, ModuleLayer.class)).invokeWithArguments(ModuleLayer.boot().configuration(), (Function<String, ClassLoader>) name -> ClassLoader.getSystemClassLoader(), ModuleLayer.boot()));
// Add all of resolved modules
modulesSet.addAll(oldBootModules);
modulesSetter.invokeWithArguments(ModuleLayer.boot().configuration(), Set.copyOf(modulesSet));
// Reset cache of boot module layer
implLookup.findSetter(ModuleLayer.class, "modules", Set.class).invokeWithArguments(ModuleLayer.boot(), null);
implLookup.findSetter(ModuleLayer.class, "servicesCatalog", Class.forName("jdk.internal.module.ServicesCatalog")).invokeWithArguments(ModuleLayer.boot(), null);
// Add reads from extra modules to jdk modules
var implAddReadsMH = implLookup.findVirtual(Module.class, "implAddReads", MethodType.methodType(void.class, Module.class));
config.modules().forEach(rm -> ModuleLayer.boot().findModule(rm.name()).ifPresent(m -> oldBootModules.forEach(brm -> ModuleLayer.boot().findModule(brm.name()).ifPresent(bm -> {
try {
implAddReadsMH.invokeWithArguments(m, bm);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}))));
// Add opens and exports, securejarhandler requires it
ModuleLayer.boot().findModule("cpw.mods.securejarhandler").ifPresent(m -> {
try {
implLookup.findVirtual(Module.class, "implAddExports", MethodType.methodType(void.class, String.class, Module.class)).invokeWithArguments(Object.class.getModule(), "sun.security.util", m);
implLookup.findVirtual(Module.class, "implAddOpens", MethodType.methodType(void.class, String.class, Module.class)).invokeWithArguments(Object.class.getModule(), "java.util.jar", m);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
});
// Launch
implLookup.findStatic(Class.forName("cpw.mods.bootstraplauncher.BootstrapLauncher"), "main", MethodType.methodType(void.class, String[].class)).invokeWithArguments(new Object[] { args });
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment