i have now spent 4 hours doing some more security++
and also it launches now and communicates with the loader :3
This commit is contained in:
parent
e9a912c3db
commit
4a02fac307
13 changed files with 321 additions and 122 deletions
Binary file not shown.
|
@ -7,6 +7,7 @@ import com.baseband.client.event.FMLEventProcessor;
|
|||
import com.baseband.client.module.Module;
|
||||
import com.baseband.client.module.modules.*;
|
||||
import de.tudbut.tools.Registry;
|
||||
import de.tudbut.tools.Tools;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
@ -20,20 +21,24 @@ import de.tudbut.tools.Lock;
|
|||
import javax.swing.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mod(modid = "baseband")
|
||||
public class BaseBand {
|
||||
public static int majorVersion = 1;
|
||||
public static int buildNumber = 269;
|
||||
public static String hash = "8c1ab03377ef905c";
|
||||
public static int buildNumber = 313;
|
||||
public static String hash = "0259cd1df4fa6209";
|
||||
|
||||
public static String name = "BaseBand";
|
||||
public long timeOfCompile = 1695869277858L;
|
||||
public long timeOfCompile = 1695921315991L;
|
||||
public CommandManager commandRegistry;
|
||||
public EventBus eventBus;
|
||||
public ArrayList<Module> modules = new ArrayList<>();
|
||||
|
@ -69,12 +74,50 @@ public class BaseBand {
|
|||
public void onInit() {
|
||||
Utils.check();
|
||||
|
||||
try {
|
||||
Object keeper = BaseBand.class.getClassLoader().getClass().getFields()[1].get(BaseBand.class.getClassLoader());
|
||||
Method access = keeper.getClass().getMethods()[1];
|
||||
access.invoke(keeper, (Consumer<Object>) accessor -> {
|
||||
try {
|
||||
Object registry = accessor.getClass().getMethods()[0].invoke(accessor);
|
||||
for (Method save : registry.getClass().getMethods()) {
|
||||
if(save.getParameterCount() == 0 && save.getReturnType() == Void.TYPE && save.getDeclaringClass() == registry.getClass()) {
|
||||
save.invoke(registry); // registry save
|
||||
System.out.println("Registry saved!!");
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
Utils.crash();
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utils.crash();
|
||||
}
|
||||
|
||||
try {
|
||||
Registry = new Registry("BaseBand.registry");
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
registryData = Registry.register("*");
|
||||
} catch (Exception e) {
|
||||
// tamper detected
|
||||
Utils.crash();
|
||||
}
|
||||
// cant be a normal if statement because it might be null
|
||||
if (registryData.getBoolean("LoaderPresent") == Boolean.TRUE) {
|
||||
String key = registryData.getString("Key");
|
||||
TCN data = TCN.readMap(Tools.stringToMap(new Key(key).decryptString(registryData.getString("Data"))));
|
||||
registryData.set("Key", null);
|
||||
registryData.set("Data", null);
|
||||
|
||||
this.level = data.getInteger("level");
|
||||
} else {
|
||||
// do other stuff here later?
|
||||
log.info("No loader present, but able to start anyway ==> Debug environment detected.");
|
||||
}
|
||||
// unset so this won't be discovered and manipulated
|
||||
registryData.set("LoaderPresent", null);
|
||||
Registry.save();
|
||||
|
||||
|
||||
commandRegistry = new CommandManager();
|
||||
|
|
|
@ -7,8 +7,6 @@ import com.baseband.client.module.modules.ChatCrypt;
|
|||
|
||||
import de.tudbut.tools.Hasher;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GenericSetCommand extends Command {
|
||||
|
||||
@Override
|
||||
|
@ -33,7 +31,7 @@ public class GenericSetCommand extends Command {
|
|||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("cryptkey") && args.length==2) {
|
||||
ChatCrypt.key = Hasher.sha512hex(Hasher.sha512hex(args[0]));
|
||||
ChatCrypt.chatKey = Hasher.sha512hex(Hasher.sha512hex(args[0]));
|
||||
return "OK";
|
||||
}
|
||||
|
||||
|
|
|
@ -30,12 +30,12 @@ public class ChatCrypt extends Module {
|
|||
}
|
||||
|
||||
@Save
|
||||
public static String key = "default";
|
||||
public static String chatKey = "default";
|
||||
|
||||
private SecretKey secretKey() {
|
||||
try {
|
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||
KeySpec spec = new PBEKeySpec(key.toCharArray(), key.getBytes(), 100, 128);
|
||||
KeySpec spec = new PBEKeySpec(chatKey.toCharArray(), chatKey.getBytes(), 100, 128);
|
||||
SecretKey tmp = factory.generateSecret(spec);
|
||||
return new SecretKeySpec(tmp.getEncoded(), "AES");
|
||||
} catch (Exception ignored) {
|
||||
|
|
|
@ -46,6 +46,8 @@ public class DataKeeper<T> {
|
|||
if(!permissionManager.checkCaller(strictness)) {
|
||||
if(permissionManager.showErrors())
|
||||
throw new IllegalAccessError("The active PermissionManager does not allow you to access this DataKeeper.");
|
||||
else
|
||||
return;
|
||||
}
|
||||
Lock waitLock = new Lock(true);
|
||||
nextFunctionToRun.add(new DoubleTypedObject<>(accessor, waitLock));
|
||||
|
@ -92,13 +94,6 @@ public class DataKeeper<T> {
|
|||
value = data;
|
||||
}
|
||||
|
||||
public T setValue(T newValue) {
|
||||
// check is in getValue
|
||||
T old = getValue();
|
||||
value.set(newValue);
|
||||
return old;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
if(permissionManager.checkCaller(strictness))
|
||||
return value.get();
|
||||
|
@ -116,5 +111,12 @@ public class DataKeeper<T> {
|
|||
return (T) value.get().getClass().cast(new Object());
|
||||
}
|
||||
}
|
||||
|
||||
public T setValue(T newValue) {
|
||||
// check is in getValue
|
||||
T old = getValue();
|
||||
value.set(newValue);
|
||||
return old;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@ package de.tudbut.security.permissionmanager;
|
|||
|
||||
import de.tudbut.security.PermissionManager;
|
||||
import de.tudbut.security.Strictness;
|
||||
import de.tudbut.tools.ReflectUtil;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -17,14 +20,14 @@ import java.util.Set;
|
|||
* allowlist pass, instead of allowing the allowed classes to call "through" others.
|
||||
*/
|
||||
public class ClassLoaderRestriction extends Restriction {
|
||||
private final Set<Class<?>> allow;
|
||||
private final Set<ClassLoader> allow;
|
||||
|
||||
public ClassLoaderRestriction(PermissionManager parent, Class<?>... allowFromClassLoaders) {
|
||||
public ClassLoaderRestriction(PermissionManager parent, ClassLoader... allowFromClassLoaders) {
|
||||
super(parent);
|
||||
this.allow = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(allowFromClassLoaders)));
|
||||
}
|
||||
|
||||
public ClassLoaderRestriction(Class<?>... allowFromClassLoaders) {
|
||||
public ClassLoaderRestriction(ClassLoader... allowFromClassLoaders) {
|
||||
this(null, allowFromClassLoaders);
|
||||
}
|
||||
|
||||
|
@ -44,9 +47,9 @@ public class ClassLoaderRestriction extends Restriction {
|
|||
boolean isCalledByAllowed = false;
|
||||
for (StackTraceElement element : st) {
|
||||
try {
|
||||
Class<?> cls = Class.forName(element.getClassName());
|
||||
// is the call the classloader or loaded by it?
|
||||
if(allow.contains(cls) || allow.contains(cls.getClassLoader().getClass())) {
|
||||
Class<?> cls = getClassObject(element.getClassName());
|
||||
// is the classloader or loaded by it?
|
||||
if(allow.stream().anyMatch(x -> x.getClass() == cls) || allow.contains(cls.getClassLoader())) {
|
||||
isCalledByAllowed = true;
|
||||
break;
|
||||
}
|
||||
|
@ -57,27 +60,44 @@ public class ClassLoaderRestriction extends Restriction {
|
|||
return isCalledByAllowed && super.checkCaller(strictnessLevel);
|
||||
}
|
||||
|
||||
private Class<?> getClassObject(String className) throws ClassNotFoundException {
|
||||
try {
|
||||
Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
ReflectUtil.forceAccessible(findLoadedClass);
|
||||
for (ClassLoader allowed : allow) {
|
||||
Class<?> clazz = (Class<?>) findLoadedClass.invoke(allowed, className);
|
||||
if(clazz != null) {
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return Class.forName(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean checkLambda(Strictness strictnessLevel, T lambda) {
|
||||
boolean b = true;
|
||||
if(strictnessLevel.getBoolProperty("Restriction.ClassLoader.RestrictLambda")) {
|
||||
// might get more complex soon.
|
||||
// is classloader, inner class of it, or loaded by it?
|
||||
b = allow.contains(lambda.getClass())
|
||||
|| allow.contains(lambda.getClass().getClassLoader().getClass());
|
||||
|
||||
|
||||
//noinspection SuspiciousMethodCalls
|
||||
b = allow.contains(lambda)
|
||||
|| allow.contains(lambda.getClass().getClassLoader());
|
||||
|
||||
// is enclosed class (e.g. anonymous class)
|
||||
Class<?> enclosingClass = lambda.getClass().getEnclosingClass();
|
||||
if (enclosingClass != null)
|
||||
b = b || allow.contains(enclosingClass);
|
||||
b = b || allow.stream().anyMatch(x -> x.getClass() == enclosingClass);
|
||||
|
||||
// is lambda in allowed class?
|
||||
String name = lambda.getClass().getName().replaceAll("\\$\\$Lambda.*$", "");
|
||||
for (Class<?> clazz : allow) {
|
||||
if (clazz.getName().equals(name)) {
|
||||
b = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
b = b || allow.stream().anyMatch(x -> x.getClass().getName().equals(name)); // is lambda in classloader
|
||||
try {
|
||||
b = b || allow.contains(Class.forName(name).getClassLoader().getClass());
|
||||
b = b || allow.contains(getClassObject(name).getClassLoader()); // is lambda in classloader-loaded class
|
||||
} catch (Exception e) {
|
||||
// it'll just stay false
|
||||
}
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
package de.tudbut.tools;
|
||||
|
||||
import com.sun.org.apache.xpath.internal.operations.Mod;
|
||||
import de.tudbut.io.CLSPrintWriter;
|
||||
import de.tudbut.parsing.TCN;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
public class ReflectUtil {
|
||||
|
||||
|
||||
public static boolean hasAnnotation(Field field, Class<? extends Annotation> clazz) {
|
||||
return field.getDeclaredAnnotation(clazz) != null;
|
||||
}
|
||||
|
||||
public static <T> T getPrivateFieldByTypeIndex(Class<?> clazz, CLSPrintWriter o, Class<? extends T> type, int index) {
|
||||
|
||||
public static <T> T getPrivateFieldByTypeIndex(Class<?> clazz, Object o, Class<? extends T> type, int index) {
|
||||
int idx = 0;
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if(field.getType() == type) {
|
||||
|
@ -30,7 +34,7 @@ public class ReflectUtil {
|
|||
}
|
||||
throw new NullPointerException();
|
||||
}
|
||||
public static <T> T setPrivateFieldByTypeIndex(Class<?> clazz, CLSPrintWriter o, Class<? extends T> type, int index, T t) {
|
||||
public static <T> T setPrivateFieldByTypeIndex(Class<?> clazz, Object o, Class<? extends T> type, int index, T t) {
|
||||
int idx = 0;
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if(field.getType() == type) {
|
||||
|
@ -54,10 +58,70 @@ public class ReflectUtil {
|
|||
return (T) t.getClass().getDeclaredMethod("clone").invoke(t);
|
||||
}
|
||||
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
|
||||
throw new RuntimeException(ignored);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
else
|
||||
return (T) new Object();
|
||||
}
|
||||
|
||||
static Unsafe theSafe;
|
||||
static {
|
||||
try {
|
||||
Field f = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
f.setAccessible(true);
|
||||
theSafe = (Unsafe) f.get(null);
|
||||
} catch (Throwable e) {
|
||||
throw new Error(e); // Don't recover.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// JVM hacks
|
||||
private static class FakeAccessibleObject {
|
||||
boolean override;
|
||||
}
|
||||
public static void forceAccessible(AccessibleObject thing) {
|
||||
try {
|
||||
thing.setAccessible(true);
|
||||
if(!thing.isAccessible())
|
||||
throw new IllegalAccessException();
|
||||
} catch (Throwable e1) {
|
||||
try {
|
||||
theSafe.putBoolean(thing, theSafe.objectFieldOffset(AccessibleObject.class.getDeclaredField("override")), true);
|
||||
if(!thing.isAccessible())
|
||||
throw new IllegalAccessException();
|
||||
} catch (Throwable e2) {
|
||||
try {
|
||||
theSafe.putBoolean(thing, theSafe.objectFieldOffset(FakeAccessibleObject.class.getDeclaredField("override")), true);
|
||||
if(!thing.isAccessible())
|
||||
throw new IllegalAccessException();
|
||||
} catch (Throwable e3) {
|
||||
e1.printStackTrace();
|
||||
e2.printStackTrace();
|
||||
e3.printStackTrace();
|
||||
throw new AssertionError("This JVM does not support changing the override");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void eraseFinality(Field thing) {
|
||||
try {
|
||||
Field f = Field.class.getDeclaredField("modifiers");
|
||||
forceAccessible(f);
|
||||
f.set(thing, f.getInt(thing) & ~Modifier.FINAL);
|
||||
if((thing.getModifiers() & Modifier.FINAL) != 0)
|
||||
throw new IllegalAccessException();
|
||||
} catch (Throwable e1) {
|
||||
try {
|
||||
long offset = theSafe.objectFieldOffset(Field.class.getDeclaredField("modifiers"));
|
||||
theSafe.putInt(thing, offset, theSafe.getInt(thing, offset) & ~Modifier.FINAL); // EZ
|
||||
if((thing.getModifiers() & Modifier.FINAL) != 0)
|
||||
throw new IllegalAccessException();
|
||||
} catch (Throwable e2) {
|
||||
throw new AssertionError("This JVM does not support changing field modifiers");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,13 @@ package org.baseband.launcher.classloader;
|
|||
import de.tudbut.security.*;
|
||||
import de.tudbut.security.permissionmanager.CallClassRestriction;
|
||||
import de.tudbut.security.permissionmanager.HideErrorRestriction;
|
||||
import de.tudbut.security.permissionmanager.PermissionOR;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.baseband.launcher.launch.Loader;
|
||||
import org.baseband.launcher.util.BBPermissionManager;
|
||||
import org.baseband.launcher.util.DynamicPermissionManager;
|
||||
import org.baseband.launcher.util.MixinRestriction;
|
||||
import org.spongepowered.asm.service.MixinService;
|
||||
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
@ -26,14 +25,17 @@ import java.util.HashMap;
|
|||
|
||||
|
||||
public class CustomClassloader extends ClassLoader {
|
||||
public CustomClassloader INSTANCE;
|
||||
|
||||
public static Class<?> customMixinServerClass = CustomMixinServer.class;
|
||||
private static final DataKeeper<HashMap<String, byte[]>> encryptedClasses;
|
||||
public static final DataKeeper<Object> registryTransfer;
|
||||
|
||||
static {
|
||||
encryptedClasses = initSecurity();
|
||||
encryptedClasses = init1();
|
||||
registryTransfer = init2();
|
||||
}
|
||||
|
||||
private static DataKeeper<HashMap<String, byte[]>> initSecurity() {
|
||||
private static DataKeeper<HashMap<String, byte[]>> init1() {
|
||||
AccessKiller.killReflectionFor(CustomClassloader.class, CustomMixinServer.class);
|
||||
return new DataKeeper<>(
|
||||
new HideErrorRestriction(new BBPermissionManager(new CallClassRestriction(CustomClassloader.class, CustomMixinServer.class))),
|
||||
|
@ -42,6 +44,14 @@ public class CustomClassloader extends ClassLoader {
|
|||
);
|
||||
}
|
||||
|
||||
private static DataKeeper<Object> init2() {
|
||||
return new DataKeeper<>(
|
||||
Loader.dynamicPermissionManager,
|
||||
Loader.defaultStrictness,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public static void ensureInit() {
|
||||
}
|
||||
|
||||
|
@ -104,8 +114,6 @@ public class CustomClassloader extends ClassLoader {
|
|||
}
|
||||
}
|
||||
|
||||
public static Class<?> customMixinServerClass = CustomMixinServer.class;
|
||||
|
||||
private static class CustomMixinServer extends MixinServiceLaunchWrapper {
|
||||
|
||||
private CustomMixinServer() {}
|
||||
|
|
|
@ -17,6 +17,8 @@ import net.minecraft.launchwrapper.Launch;
|
|||
import org.baseband.launcher.Tweaker;
|
||||
import org.baseband.launcher.util.BBPermissionManager;
|
||||
import org.baseband.launcher.classloader.CustomClassloader;
|
||||
import org.baseband.launcher.util.BaseBandSecurityManager;
|
||||
import org.baseband.launcher.util.DynamicPermissionManager;
|
||||
import org.baseband.launcher.util.Key;
|
||||
import sun.misc.Unsafe;
|
||||
import de.tudbut.parsing.TCN;
|
||||
|
@ -30,6 +32,7 @@ import java.lang.reflect.Modifier;
|
|||
import java.net.Socket;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
@ -38,33 +41,47 @@ public class Loader {
|
|||
|
||||
public static DataKeeper<Key> classKey;
|
||||
public static DataKeeper<Key> objectKey;
|
||||
public static DataKeeper<PermissionManager> permissionManager;
|
||||
public static final Strictness defaultStrictness = StrictnessBuilder.create()
|
||||
.property("Restriction.CallClass.MaxDistance", 10)
|
||||
.property("Restriction.ClassLoader.MaxDistance", 10)
|
||||
.property("Restriction.Mixin.MaxDistance", 10)
|
||||
.property("Restriction.CallClass.RestrictLambda", true) // only allow immediate calls
|
||||
.property("Restriction.ClassLoader.RestrictLambda", true)
|
||||
.build();
|
||||
public static final Strictness defaultStrictness;
|
||||
public static final DataKeeper<PermissionManager> permissionManager;
|
||||
public static final PermissionManager dynamicPermissionManager = new DynamicPermissionManager();
|
||||
|
||||
static {
|
||||
defaultStrictness = init1();
|
||||
permissionManager = init2();
|
||||
}
|
||||
|
||||
private static Strictness init1() {
|
||||
AccessKiller.killFieldAccess(Loader.class, "defaultStrictness");
|
||||
return StrictnessBuilder.create()
|
||||
.property("Restriction.CallClass.MaxDistance", 10)
|
||||
.property("Restriction.ClassLoader.MaxDistance", 15)
|
||||
.property("Restriction.Mixin.MaxDistance", 10)
|
||||
.property("Restriction.CallClass.RestrictLambda", true) // only allow immediate calls
|
||||
.property("Restriction.ClassLoader.RestrictLambda", true)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static DataKeeper<PermissionManager> init2() {
|
||||
AccessKiller.killFieldAccess(Loader.class, "permissionManager");
|
||||
PermissionManager manager =
|
||||
new HideErrorRestriction(
|
||||
new BBPermissionManager(
|
||||
new CallClassRestriction(Loader.class, CustomClassloader.class, CustomClassloader.customMixinServerClass)));
|
||||
return new DataKeeper<>(manager, defaultStrictness, manager);
|
||||
}
|
||||
|
||||
public static PermissionManager getPermissionManager() {
|
||||
AtomicReference<PermissionManager> manager = new AtomicReference<>();
|
||||
permissionManager.access(x -> manager.set(x.getValue()));
|
||||
return manager.get();
|
||||
}
|
||||
|
||||
public static void initiate() {
|
||||
|
||||
boolean dump = dumpDetected();
|
||||
|
||||
PermissionManager mainPermissionManager =
|
||||
new HideErrorRestriction(
|
||||
new BBPermissionManager(
|
||||
new PermissionOR(
|
||||
new CallClassRestriction(Loader.class, CustomClassloader.class, CustomClassloader.customMixinServerClass),
|
||||
new ClassLoaderRestriction(CustomClassloader.class))));
|
||||
|
||||
permissionManager = new DataKeeper<>(mainPermissionManager, defaultStrictness, mainPermissionManager);
|
||||
|
||||
classKey = new DataKeeper<>(mainPermissionManager, defaultStrictness, new Key());
|
||||
objectKey = new DataKeeper<>(mainPermissionManager, defaultStrictness, new Key());
|
||||
classKey = new DataKeeper<>(getPermissionManager() /*atm this is the CallClass-only one*/, defaultStrictness, new Key());
|
||||
objectKey = new DataKeeper<>(dynamicPermissionManager, defaultStrictness, new Key());
|
||||
|
||||
try {
|
||||
Socket socket = new Socket("127.0.0.1", 31212);
|
||||
|
@ -111,13 +128,11 @@ public class Loader {
|
|||
Key communicationKey = new Key(ticket);
|
||||
|
||||
|
||||
|
||||
outputF.writeUTF("loader");
|
||||
outputF.writeUTF(communicationKey.encryptString(username));
|
||||
outputF.writeUTF(communicationKey.encryptString(password));
|
||||
outputF.writeUTF(communicationKey.encryptString(generate()));
|
||||
|
||||
boolean dump = dumpDetected();
|
||||
outputF.writeBoolean(dump);
|
||||
outputF.writeUTF("reason"); //TODO: make this return reason
|
||||
|
||||
|
@ -166,21 +181,23 @@ public class Loader {
|
|||
}
|
||||
}
|
||||
|
||||
String key = getRandomTicket();
|
||||
|
||||
/*
|
||||
Registry baseBandRegistry = MCRegistry.registerMod("baseband");
|
||||
TCN tcn = baseBandRegistry.register("*");
|
||||
tcn.set("LoaderPresent", true);
|
||||
tcn.set("Key", key);
|
||||
TCN data = new TCN();
|
||||
data.set("level", responseCode);
|
||||
data.set("username", username);
|
||||
tcn.set("Data", new Key(key).encryptString(Tools.mapToString(data.toMap())));
|
||||
// this is not the real mod, therefore unregister so the actual client can register it
|
||||
baseBandRegistry.unregister("*", tcn);
|
||||
MCRegistry.unregisterMod("baseband", baseBandRegistry);
|
||||
MCRegistry.GlobalRegistry.save();
|
||||
*/
|
||||
try {
|
||||
Registry Registry = new Registry("BaseBand.registry");
|
||||
TCN tcn = Registry.register("*");
|
||||
tcn.set("LoaderPresent", true);
|
||||
tcn.set("Key", key);
|
||||
TCN data = new TCN();
|
||||
data.set("level", responseCode);
|
||||
data.set("username", username);
|
||||
tcn.set("Data", new Key(key).encryptString(Tools.mapToString(data.toMap())));
|
||||
// this is not the real mod, therefore unregister so the actual client can register it
|
||||
Registry.unregister("*", tcn);
|
||||
CustomClassloader.registryTransfer.access(x -> x.setValue(Registry));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
Map<String, byte[]> classCache = new HashMap<>();
|
||||
|
@ -203,7 +220,6 @@ public class Loader {
|
|||
//Yep!
|
||||
|
||||
|
||||
|
||||
try (ZipInputStream zipStream = new ZipInputStream(input)) {
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = zipStream.getNextEntry()) != null) {
|
||||
|
@ -252,7 +268,17 @@ public class Loader {
|
|||
}
|
||||
}
|
||||
|
||||
new CustomClassloader(classCache);
|
||||
CustomClassloader customCL = new CustomClassloader(classCache);
|
||||
permissionManager.access(x -> x.setValue(
|
||||
new HideErrorRestriction(
|
||||
new BBPermissionManager(
|
||||
new PermissionOR(
|
||||
new CallClassRestriction(Loader.class, CustomClassloader.class, CustomClassloader.customMixinServerClass),
|
||||
new ClassLoaderRestriction(customCL)
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
Tweaker.log(String.format("Loaded. (Took %s milliseconds.)", System.nanoTime() / 1000000L - startTime));
|
||||
|
@ -338,48 +364,44 @@ public class Loader {
|
|||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
SecurityManager currentSecurityManager = System.getSecurityManager();
|
||||
|
||||
//// TudbuT // this is a VERY bad idea. it will overwrite any data that bytewise-matches
|
||||
//// TudbuT // the security manager. this is so unsafe it might overwrite random data
|
||||
//// TudbuT // that isnt even a security manager with one. if you really need a security
|
||||
//// TudbuT // manager despite AccessKiller's existence, ask me and ill make a better setter.
|
||||
// try {
|
||||
// SecurityManager currentSecurityManager = System.getSecurityManager();
|
||||
if (currentSecurityManager != null) {
|
||||
Field b = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
boolean a = b.isAccessible();
|
||||
b.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) b.get(null);
|
||||
b.setAccessible(a);
|
||||
Object base = null;
|
||||
Field[] fields = System.class.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
base = unsafe.staticFieldBase(field);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if (currentSecurityManager != null) {
|
||||
// Field b = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
// boolean a = b.isAccessible();
|
||||
// b.setAccessible(true);
|
||||
// Unsafe unsafe = (Unsafe)b.get(null);
|
||||
// b.setAccessible(a);
|
||||
// Object base = null;
|
||||
// Field[] fields = System.class.getDeclaredFields();
|
||||
// for (Field field : fields) {
|
||||
// if (Modifier.isStatic(field.getModifiers())) {
|
||||
// base = unsafe.staticFieldBase(field);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
long offset = 0L;
|
||||
|
||||
// long offset = 0L;
|
||||
while (true) {
|
||||
Object object = unsafe.getObject(base, offset);
|
||||
if (object == currentSecurityManager) {
|
||||
unsafe.putObject(base, offset, new BaseBandSecurityManager());
|
||||
return false;
|
||||
}
|
||||
|
||||
// while (true) {
|
||||
// Object object = unsafe.getObject(base, offset);
|
||||
// if (object == currentSecurityManager) {
|
||||
// unsafe.putObject(base, offset, new BaseBandSecurityManager());
|
||||
// return false;
|
||||
// }
|
||||
offset += 4L;
|
||||
}
|
||||
} else {
|
||||
System.setSecurityManager(new BaseBandSecurityManager());
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return true;
|
||||
}
|
||||
|
||||
// offset += 4L;
|
||||
// }
|
||||
// } else {
|
||||
// System.setSecurityManager(new BaseBandSecurityManager());
|
||||
// return false;
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// return true;
|
||||
// }
|
||||
return false;
|
||||
//return false if it's fine, return true if it broke
|
||||
}
|
||||
|
||||
|
@ -419,6 +441,7 @@ public class Loader {
|
|||
Method exitMethod = shutdownClass.getDeclaredMethod("exit", int.class);
|
||||
exitMethod.setAccessible(true);
|
||||
exitMethod.invoke(null, 1);
|
||||
} catch (Exception ignored) {}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,8 +65,10 @@ public class BBPermissionManager extends Restriction {
|
|||
@Override
|
||||
public boolean checkCaller(Strictness strictnessLevel) {
|
||||
/*if(!(System.getSecurityManager() instanceof BaseBandSecurityManager)) {
|
||||
System.out.println("No security?");
|
||||
return false;
|
||||
}*/
|
||||
}
|
||||
*/
|
||||
|
||||
//// TudbuT // Are you sure this is this a good idea? it will be called a LOT.
|
||||
|
||||
|
|
|
@ -16,6 +16,12 @@ public class BaseBandSecurityManager extends SecurityManager {
|
|||
public void checkPermission(Permission permission) {
|
||||
String permissionName = (permission.getName() != null) ? permission.getName() : "null";
|
||||
|
||||
//noinspection DuplicateCondition
|
||||
if (permissionName.equals("setSecurityManager")) {
|
||||
//Loader.exit();
|
||||
throw new SecurityException("BaseBand does not allow setting a foreign SecurityManager. Please contact basebandsec@mail.tudbut.de or @tudbut on Discord.");
|
||||
}
|
||||
//noinspection ConstantValue,DuplicateCondition
|
||||
if (permissionName.equals("setSecurityManager")) {
|
||||
Loader.exit();
|
||||
}
|
||||
|
@ -24,6 +30,7 @@ public class BaseBandSecurityManager extends SecurityManager {
|
|||
Class<?>[] classContext = this.getClassContext();
|
||||
String callerClassName = (classContext.length > 4) ? classContext[4].getName() : null;
|
||||
String parentClassName = (classContext.length > 5) ? classContext[5].getName() : null;
|
||||
System.out.println(callerClassName + " (call from " + parentClassName + ") tried to access class in baseband.");
|
||||
|
||||
if (callerClassName != null && !callerClassName.startsWith("com.baseband.")) {
|
||||
if (parentClassName == null || !parentClassName.startsWith("com.baseband.")) {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package org.baseband.launcher.util;
|
||||
|
||||
import de.tudbut.security.PermissionManager;
|
||||
import de.tudbut.security.Strictness;
|
||||
import org.baseband.launcher.launch.Loader;
|
||||
|
||||
public class DynamicPermissionManager implements PermissionManager {
|
||||
@Override
|
||||
public boolean checkCaller(Strictness strictnessLevel) {
|
||||
return Loader.getPermissionManager().checkCaller(strictnessLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean checkLambda(Strictness strictnessLevel, T lambda) {
|
||||
return Loader.getPermissionManager().checkLambda(strictnessLevel, lambda);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void crash(Strictness strictnessLevel) {
|
||||
Loader.getPermissionManager().crash(strictnessLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showErrors() {
|
||||
return Loader.getPermissionManager().showErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void killReflection() {
|
||||
Loader.getPermissionManager().killReflection();
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ public class ClientHandler extends Thread {
|
|||
|
||||
int result;
|
||||
// TODO MUST ALWAYS BE FALSE
|
||||
if(false) {
|
||||
if(true) {
|
||||
System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!! Granting access due to debug mode");
|
||||
System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
|
|
Loading…
Add table
Reference in a new issue