ohmygod
:3
This commit is contained in:
parent
227c76bfff
commit
2bb0d88e64
11 changed files with 414 additions and 125 deletions
|
@ -6,9 +6,7 @@ import com.baseband.client.event.EventBus;
|
||||||
import com.baseband.client.event.FMLEventProcessor;
|
import com.baseband.client.event.FMLEventProcessor;
|
||||||
import com.baseband.client.module.Module;
|
import com.baseband.client.module.Module;
|
||||||
import com.baseband.client.module.modules.*;
|
import com.baseband.client.module.modules.*;
|
||||||
import de.tudbut.mcregistry.MCRegistry;
|
|
||||||
import de.tudbut.tools.Registry;
|
import de.tudbut.tools.Registry;
|
||||||
import de.tudbut.tools.Tools;
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.launchwrapper.Launch;
|
import net.minecraft.launchwrapper.Launch;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
@ -31,11 +29,11 @@ import java.util.ArrayList;
|
||||||
@Mod(modid = "baseband")
|
@Mod(modid = "baseband")
|
||||||
public class BaseBand {
|
public class BaseBand {
|
||||||
public static int majorVersion = 1;
|
public static int majorVersion = 1;
|
||||||
public static int buildNumber = 189;
|
public static int buildNumber = 195;
|
||||||
public static String hash = "19a91abc85a04461";
|
public static String hash = "996032a4408f699a";
|
||||||
|
|
||||||
public static String name = "BaseBand";
|
public static String name = "BaseBand";
|
||||||
public long timeOfCompile = 1695669761860L;
|
public long timeOfCompile = 1695766816016L;
|
||||||
public CommandManager commandRegistry;
|
public CommandManager commandRegistry;
|
||||||
public EventBus eventBus;
|
public EventBus eventBus;
|
||||||
public ArrayList<Module> modules = new ArrayList<>();
|
public ArrayList<Module> modules = new ArrayList<>();
|
||||||
|
@ -73,27 +71,7 @@ public class BaseBand {
|
||||||
|
|
||||||
downloadMCRegistry();
|
downloadMCRegistry();
|
||||||
|
|
||||||
try {
|
|
||||||
Registry = MCRegistry.registerMod("baseband");
|
|
||||||
registryData = Registry.register("*");
|
|
||||||
} catch (Exception e) {
|
|
||||||
// tamper detected
|
|
||||||
Utils.crash();
|
|
||||||
}
|
|
||||||
// cant be a normal if statement because it might be null
|
|
||||||
if (registryData.get("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);
|
|
||||||
|
|
||||||
commandRegistry = new CommandManager();
|
commandRegistry = new CommandManager();
|
||||||
eventBus = new EventBus();
|
eventBus = new EventBus();
|
||||||
|
@ -162,7 +140,7 @@ public class BaseBand {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addModule(Module m) {
|
public void addModule(Module m) {
|
||||||
Restrict annotation = m.getClass().getDeclaredAnnotation(Restrict.class)
|
Restrict annotation = m.getClass().getDeclaredAnnotation(Restrict.class);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
if(level < annotation.value().level)
|
if(level < annotation.value().level)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -71,8 +71,8 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a tweaker, so it can go into the jar
|
// this is a tweaker, so it can go into the jar
|
||||||
jarLibs files('libs/mcregistry-1.0.jar')
|
//jarLibs files('libs/mcregistry-1.0.jar')
|
||||||
|
//No
|
||||||
|
|
||||||
annotationProcessor('org.spongepowered:mixin:0.8.5:processor') {
|
annotationProcessor('org.spongepowered:mixin:0.8.5:processor') {
|
||||||
exclude module: 'gson'
|
exclude module: 'gson'
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Jess H & Daniella H. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Unauthorized copying of this file via any medium is Strictly Prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.baseband.launcher;
|
package org.baseband.launcher;
|
||||||
|
|
||||||
import net.minecraft.launchwrapper.ITweaker;
|
import net.minecraft.launchwrapper.ITweaker;
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
package org.baseband.launcher.util;
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Jess H & Daniella H. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Unauthorized copying of this file via any medium is Strictly Prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.baseband.launcher.classloader;
|
||||||
|
|
||||||
import net.minecraft.launchwrapper.Launch;
|
import net.minecraft.launchwrapper.Launch;
|
||||||
import org.baseband.launcher.launch.Loader;
|
import org.baseband.launcher.launch.Loader;
|
||||||
|
import org.baseband.launcher.util.security.SecureContainer;
|
||||||
import org.spongepowered.asm.service.MixinService;
|
import org.spongepowered.asm.service.MixinService;
|
||||||
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
|
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
|
||||||
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
@ -12,8 +21,7 @@ import java.util.HashMap;
|
||||||
|
|
||||||
|
|
||||||
public class CustomClassloader extends ClassLoader {
|
public class CustomClassloader extends ClassLoader {
|
||||||
public CustomClassloader INSTANCE;
|
private static SecureContainer<Object> encryptedClasses;
|
||||||
private static final DataKeeper<HashMap<String, byte[]>> encryptedClasses = new DataKeeper<>(new HashMap<>(), true);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,9 +29,9 @@ public class CustomClassloader extends ClassLoader {
|
||||||
initClasses(obj);
|
initClasses(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CustomClassloader() {}
|
|
||||||
|
|
||||||
public void initClasses(Object classes){
|
public void initClasses(Object classes){
|
||||||
|
encryptedClasses = new SecureContainer<>(new HashMap<>(), true);
|
||||||
try {
|
try {
|
||||||
CustomMixinServer customService = new CustomMixinServer();
|
CustomMixinServer customService = new CustomMixinServer();
|
||||||
Class<?> mixinServiceClass = Class.forName("org.spongepowered.asm.service.MixinService");
|
Class<?> mixinServiceClass = Class.forName("org.spongepowered.asm.service.MixinService");
|
||||||
|
@ -41,17 +49,13 @@ public class CustomClassloader extends ClassLoader {
|
||||||
Loader.exit();
|
Loader.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANCE = new CustomClassloader();
|
encryptedClasses.access(accessor -> accessor.setValue(classes));
|
||||||
//CustomClassloader.classes = classes;
|
|
||||||
|
|
||||||
encryptedClasses.access(accessor -> accessor.setValue((HashMap<String, byte[]>) classes));
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Field parent = ClassLoader.class.getDeclaredField("parent");
|
Field parent = ClassLoader.class.getDeclaredField("parent");
|
||||||
parent.setAccessible(true);
|
parent.setAccessible(true);
|
||||||
parent.set(INSTANCE, parent.get(Launch.classLoader));
|
parent.set(this, parent.get(Launch.classLoader));
|
||||||
parent.set(Launch.classLoader, INSTANCE);
|
parent.set(Launch.classLoader, this);
|
||||||
} catch (IllegalAccessException | NoSuchFieldException var6) {
|
} catch (IllegalAccessException | NoSuchFieldException var6) {
|
||||||
var6.printStackTrace();
|
var6.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -62,13 +66,20 @@ public class CustomClassloader extends ClassLoader {
|
||||||
@Override
|
@Override
|
||||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
final byte[][] data = {null};
|
final byte[][] data = {null};
|
||||||
encryptedClasses.access(accessor -> data[0] = Loader.classKey.decryptByte(accessor.getValue().get(name)));
|
encryptedClasses.access(accessor -> data[0] = Loader.classKey.decryptByte(((HashMap<String, byte[]>)accessor.getValue()).get(name)));
|
||||||
if(data[0] != null) {
|
if(data[0] != null) {
|
||||||
Class<?> clazz = defineClass(name, data[0], 0, data[0].length);
|
try {
|
||||||
if (clazz == null) {
|
Field b = Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
|
Unsafe unsafe = (Unsafe)b.get(null);
|
||||||
|
Class<?> definedClass = unsafe.defineClass(name, data[0], 0, data[0].length, this, null);
|
||||||
|
|
||||||
|
if (definedClass == null) {
|
||||||
throw new ClassNotFoundException(name);
|
throw new ClassNotFoundException(name);
|
||||||
}
|
}
|
||||||
return clazz;
|
return definedClass;
|
||||||
|
}catch (Exception e){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
return Launch.classLoader.findClass(name);
|
return Launch.classLoader.findClass(name);
|
||||||
|
@ -79,12 +90,12 @@ public class CustomClassloader extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class CustomMixinServer extends MixinServiceLaunchWrapper {
|
public static class CustomMixinServer extends MixinServiceLaunchWrapper {
|
||||||
@Override
|
@Override
|
||||||
public byte[] getClassBytes(String name, String transformedName) throws IOException {
|
public byte[] getClassBytes(String name, String transformedName) throws IOException {
|
||||||
if(name.startsWith("com.baseband")) {
|
if(name.startsWith("com.baseband")) {
|
||||||
final byte[][] bytes = {null};
|
final byte[][] bytes = {null};
|
||||||
encryptedClasses.access(accessor -> bytes[0] = Loader.classKey.decryptByte(accessor.getValue().get(name)));
|
encryptedClasses.access(accessor -> bytes[0] = Loader.classKey.decryptByte(((HashMap<String, byte[]>)accessor.getValue()).get(name)));
|
||||||
if (bytes[0] != null) {
|
if (bytes[0] != null) {
|
||||||
return bytes[0];
|
return bytes[0];
|
||||||
}
|
}
|
||||||
|
@ -96,7 +107,7 @@ public class CustomClassloader extends ClassLoader {
|
||||||
public byte[] getClassBytes(String name, boolean runTransformers) throws ClassNotFoundException, IOException {
|
public byte[] getClassBytes(String name, boolean runTransformers) throws ClassNotFoundException, IOException {
|
||||||
if(name.startsWith("com.baseband")) {
|
if(name.startsWith("com.baseband")) {
|
||||||
final byte[][] bytes = {null};
|
final byte[][] bytes = {null};
|
||||||
encryptedClasses.access(accessor -> bytes[0] = Loader.classKey.decryptByte(accessor.getValue().get(name)));
|
encryptedClasses.access(accessor -> bytes[0] = Loader.classKey.decryptByte(((HashMap<String, byte[]>)accessor.getValue()).get(name)));
|
||||||
if (bytes[0] != null) {
|
if (bytes[0] != null) {
|
||||||
return bytes[0];
|
return bytes[0];
|
||||||
}
|
}
|
|
@ -1,26 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Jess H & Daniella H. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Unauthorized copying of this file via any medium is Strictly Prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.baseband.launcher.launch;
|
package org.baseband.launcher.launch;
|
||||||
|
|
||||||
import de.tudbut.mcregistry.MCRegistry;
|
|
||||||
import de.tudbut.tools.Registry;
|
|
||||||
import de.tudbut.tools.Tools;
|
|
||||||
import net.minecraft.launchwrapper.Launch;
|
import net.minecraft.launchwrapper.Launch;
|
||||||
import org.baseband.launcher.Tweaker;
|
import org.baseband.launcher.Tweaker;
|
||||||
import org.baseband.launcher.util.CustomClassloader;
|
import org.baseband.launcher.util.security.BaseBandSecurityManager;
|
||||||
|
import org.baseband.launcher.classloader.CustomClassloader;
|
||||||
import org.baseband.launcher.util.Key;
|
import org.baseband.launcher.util.Key;
|
||||||
import sun.misc.Unsafe;
|
import sun.misc.Unsafe;
|
||||||
import tudbut.io.StreamRedirect;
|
|
||||||
import tudbut.parsing.TCN;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.management.ManagementFactory;
|
import java.lang.management.ManagementFactory;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.jar.JarOutputStream;
|
import java.util.jar.JarOutputStream;
|
||||||
|
@ -80,16 +79,7 @@ public class Loader {
|
||||||
objectKey = new Key();
|
objectKey = new Key();
|
||||||
|
|
||||||
|
|
||||||
if (System.getProperty("com.bb.debugKey") != null) {
|
outputF.writeUTF("loader");
|
||||||
if (System.getProperty("com.bb.debugKey").equalsIgnoreCase("true")) {
|
|
||||||
Tweaker.log("!!Warning!!\nEncryption Debug set to enabled.");
|
|
||||||
communicationKey.setDebug(true);
|
|
||||||
classKey.setDebug(true);
|
|
||||||
objectKey.setDebug(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outputF.writeUTF("loader")
|
|
||||||
outputF.writeUTF(communicationKey.encryptString(username));
|
outputF.writeUTF(communicationKey.encryptString(username));
|
||||||
outputF.writeUTF(communicationKey.encryptString(password));
|
outputF.writeUTF(communicationKey.encryptString(password));
|
||||||
outputF.writeUTF(communicationKey.encryptString(generate()));
|
outputF.writeUTF(communicationKey.encryptString(generate()));
|
||||||
|
@ -144,8 +134,7 @@ public class Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String key = getRandomTicket();
|
/*
|
||||||
|
|
||||||
Registry baseBandRegistry = MCRegistry.registerMod("baseband");
|
Registry baseBandRegistry = MCRegistry.registerMod("baseband");
|
||||||
TCN tcn = baseBandRegistry.register("*");
|
TCN tcn = baseBandRegistry.register("*");
|
||||||
tcn.set("LoaderPresent", true);
|
tcn.set("LoaderPresent", true);
|
||||||
|
@ -158,6 +147,7 @@ public class Loader {
|
||||||
baseBandRegistry.unregister("*", tcn);
|
baseBandRegistry.unregister("*", tcn);
|
||||||
MCRegistry.unregisterMod("baseband", baseBandRegistry);
|
MCRegistry.unregisterMod("baseband", baseBandRegistry);
|
||||||
MCRegistry.GlobalRegistry.save();
|
MCRegistry.GlobalRegistry.save();
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
Map<String, byte[]> classCache = new HashMap<>();
|
Map<String, byte[]> classCache = new HashMap<>();
|
||||||
|
@ -180,6 +170,7 @@ public class Loader {
|
||||||
//Yep!
|
//Yep!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try (ZipInputStream zipStream = new ZipInputStream(input)) {
|
try (ZipInputStream zipStream = new ZipInputStream(input)) {
|
||||||
ZipEntry zipEntry;
|
ZipEntry zipEntry;
|
||||||
while ((zipEntry = zipStream.getNextEntry()) != null) {
|
while ((zipEntry = zipStream.getNextEntry()) != null) {
|
||||||
|
@ -311,9 +302,46 @@ public class Loader {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long offset = 0L;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Object object = unsafe.getObject(base, offset);
|
||||||
|
if (object == currentSecurityManager) {
|
||||||
|
unsafe.putObject(base, offset, new BaseBandSecurityManager());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offset += 4L;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.setSecurityManager(new BaseBandSecurityManager());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//return false if it's fine, return true if it broke
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Unsafe getUnsafe() {
|
private static Unsafe getUnsafe() {
|
||||||
try {
|
try {
|
||||||
|
@ -350,8 +378,6 @@ public class Loader {
|
||||||
Method exitMethod = shutdownClass.getDeclaredMethod("exit", int.class);
|
Method exitMethod = shutdownClass.getDeclaredMethod("exit", int.class);
|
||||||
exitMethod.setAccessible(true);
|
exitMethod.setAccessible(true);
|
||||||
exitMethod.invoke(null, 1);
|
exitMethod.invoke(null, 1);
|
||||||
} catch (Exception b) {
|
} catch (Exception ignored) {}
|
||||||
while (true) ;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Jess H & Daniella H. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Unauthorized copying of this file via any medium is Strictly Prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.baseband.launcher.tweaker;
|
package org.baseband.launcher.tweaker;
|
||||||
|
|
||||||
import org.spongepowered.asm.launch.MixinBootstrap;
|
import org.spongepowered.asm.launch.MixinBootstrap;
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Jess H & Daniella H. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Unauthorized copying of this file via any medium is Strictly Prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.baseband.launcher.util;
|
package org.baseband.launcher.util;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class Key {
|
public class Key {
|
||||||
//Daniella made the actual encryption,
|
|
||||||
//Jess made the serialization/byte handling/randomTicket
|
|
||||||
|
|
||||||
protected final String string;
|
protected final String string;
|
||||||
|
|
||||||
private boolean debug = false;
|
|
||||||
|
|
||||||
|
|
||||||
public Key() {
|
public Key() {
|
||||||
string = getRandomTicket();
|
string = getRandomTicket();
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,6 @@ public class Key {
|
||||||
string = new String(key);
|
string = new String(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDebug(boolean debug) {
|
|
||||||
this.debug = debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getRandomTicket() {
|
private static String getRandomTicket() {
|
||||||
StringBuilder buffer = new StringBuilder();
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
@ -37,39 +34,6 @@ public class Key {
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public byte[] serializeObject(Object obj) {
|
|
||||||
try {
|
|
||||||
if(debug) {
|
|
||||||
System.out.println(obj + " serialize + encrypt");
|
|
||||||
}
|
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
||||||
ObjectOutputStream objectOut = new ObjectOutputStream(byteArrayOutputStream);
|
|
||||||
objectOut.writeObject(obj);
|
|
||||||
objectOut.close();
|
|
||||||
return encryptByte(byteArrayOutputStream.toByteArray());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null; // Return null in case of an error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object deserializeObject(byte[] bytes) {
|
|
||||||
try {
|
|
||||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decryptByte(bytes));
|
|
||||||
ObjectInputStream objectIn = new ObjectInputStream(byteArrayInputStream);
|
|
||||||
Object obj = objectIn.readObject();
|
|
||||||
objectIn.close();
|
|
||||||
if(debug) {
|
|
||||||
System.out.println(obj + " deserialize + decrypt");
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null; // Return null in case of an error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] encryptByte(byte[] bytes) {
|
public byte[] encryptByte(byte[] bytes) {
|
||||||
if(bytes == null) {
|
if(bytes == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
217
Loader/src/main/java/org/baseband/launcher/util/Lock.java
Normal file
217
Loader/src/main/java/org/baseband/launcher/util/Lock.java
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
package org.baseband.launcher.util;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for synchronization and timing
|
||||||
|
* {@code @Author} TudbuT
|
||||||
|
*/
|
||||||
|
public class Lock {
|
||||||
|
|
||||||
|
private final Locker locker = new Locker();
|
||||||
|
private boolean locked = false;
|
||||||
|
private int t = 0;
|
||||||
|
private long ts = 0;
|
||||||
|
private final AtomicInteger waiting = new AtomicInteger();
|
||||||
|
private volatile boolean[] waiterLocker = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object to handle thread locking
|
||||||
|
*/
|
||||||
|
private static class Locker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the thread wait until {@link Locker#unlock()} is called
|
||||||
|
* @throws InterruptedException Inherited from {@link Object#wait}
|
||||||
|
*/
|
||||||
|
public synchronized void lockHere() throws InterruptedException {
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the thread wait until {@link Locker#unlock()} is called or the timeout runs out
|
||||||
|
* @throws InterruptedException Inherited from {@link Object#wait}
|
||||||
|
* @param timeout Maximal wait time
|
||||||
|
*/
|
||||||
|
public synchronized void lockHere(long timeout) throws InterruptedException {
|
||||||
|
wait(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop locking
|
||||||
|
*/
|
||||||
|
public synchronized void unlock() {
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Lock without default state
|
||||||
|
*/
|
||||||
|
public Lock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Lock with default state
|
||||||
|
* @param locked Default state
|
||||||
|
*/
|
||||||
|
public Lock(boolean locked) {
|
||||||
|
this.locked = locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return The time left
|
||||||
|
*/
|
||||||
|
public long timeLeft() {
|
||||||
|
updateLocked();
|
||||||
|
return locked ? (ts + t) - new Date().getTime() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculate timeout
|
||||||
|
* @param timeout Timeout to override time
|
||||||
|
* @return Time left
|
||||||
|
*/
|
||||||
|
protected int checkTime(int timeout) {
|
||||||
|
return locked ? checkNegative(Math.min((int) (t - (new Date().getTime() - ts ) ), timeout <= 0 ? Integer.MAX_VALUE : timeout), timeout) : timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns alt if i is negative, otherwise i
|
||||||
|
* @param i The integer to check
|
||||||
|
* @param alt The alternative for if its negative
|
||||||
|
* @return The checked or overridden value
|
||||||
|
*/
|
||||||
|
protected int checkNegative(int i, int alt) {
|
||||||
|
if(i <= 0)
|
||||||
|
return alt;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is still locked?
|
||||||
|
*/
|
||||||
|
protected void updateLocked() {
|
||||||
|
if(new Date().getTime() - ts >= t && ts != 0)
|
||||||
|
locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until unlocked, either by a timer or manually
|
||||||
|
*/
|
||||||
|
public void waitHere() {
|
||||||
|
updateLocked();
|
||||||
|
if(locked) {
|
||||||
|
try {
|
||||||
|
locker.lockHere(checkTime(0));
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateLocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until unlocked, either by a timer, manually, or when it waited for timeout
|
||||||
|
* @param timeout Timeout
|
||||||
|
*/
|
||||||
|
public void waitHere(int timeout) {
|
||||||
|
updateLocked();
|
||||||
|
if(locked) {
|
||||||
|
try {
|
||||||
|
locker.lockHere(checkTime(timeout));
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateLocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlock manually
|
||||||
|
*/
|
||||||
|
public synchronized void unlock() {
|
||||||
|
locker.unlock();
|
||||||
|
locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock until manually unlocked
|
||||||
|
*/
|
||||||
|
public synchronized void lock() {
|
||||||
|
t = 0;
|
||||||
|
ts = 0;
|
||||||
|
locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock for a specific amount of time. Timer is passive.
|
||||||
|
* @param time The time to lock for
|
||||||
|
*/
|
||||||
|
public synchronized void lock(int time) {
|
||||||
|
if(time < 0)
|
||||||
|
time = 0;
|
||||||
|
locked = true;
|
||||||
|
t = time;
|
||||||
|
ts = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return If the lock is locked
|
||||||
|
*/
|
||||||
|
public synchronized boolean isLocked() {
|
||||||
|
updateLocked();
|
||||||
|
return locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronize multiple threads on this lock
|
||||||
|
* @param amount The amount of threads to synchronize
|
||||||
|
*/
|
||||||
|
public void synchronize(int amount) {
|
||||||
|
this.locked = true;
|
||||||
|
if(waiterLocker == null)
|
||||||
|
waiterLocker = new boolean[amount];
|
||||||
|
int i = waiting.get();
|
||||||
|
waiting.getAndIncrement();
|
||||||
|
locker.unlock();
|
||||||
|
while (amount > waiting.get()) {
|
||||||
|
try {
|
||||||
|
locker.lockHere();
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
locker.unlock();
|
||||||
|
boolean b;
|
||||||
|
waiterLocker[i] = true;
|
||||||
|
b = true;
|
||||||
|
try {
|
||||||
|
while (b) {
|
||||||
|
b = false;
|
||||||
|
for (int j = 0 ; j < waiterLocker.length ; j++) {
|
||||||
|
if (!waiterLocker[j]) {
|
||||||
|
b = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) { }
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
waiting.getAndDecrement();
|
||||||
|
waiterLocker = null;
|
||||||
|
this.locked = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Jess H & Daniella H. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Unauthorized copying of this file via any medium is Strictly Prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.baseband.launcher.util.security;
|
||||||
|
|
||||||
|
import org.baseband.launcher.launch.Loader;
|
||||||
|
|
||||||
|
import java.security.Permission;
|
||||||
|
|
||||||
|
public class BaseBandSecurityManager extends SecurityManager {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkPermission(Permission permission) {
|
||||||
|
String permissionName = (permission.getName() != null) ? permission.getName() : "null";
|
||||||
|
|
||||||
|
if (permissionName.equals("setSecurityManager")) {
|
||||||
|
Loader.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permissionName.startsWith("accessClassInPackage.com.baseband")) {
|
||||||
|
Class<?>[] classContext = this.getClassContext();
|
||||||
|
String callerClassName = (classContext.length > 4) ? classContext[4].getName() : null;
|
||||||
|
String parentClassName = (classContext.length > 5) ? classContext[5].getName() : null;
|
||||||
|
|
||||||
|
if (callerClassName != null && !callerClassName.startsWith("com.baseband.")) {
|
||||||
|
if (parentClassName == null || !parentClassName.startsWith("com.baseband.")) {
|
||||||
|
Loader.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkPermission(Permission b, Object a) {
|
||||||
|
checkPermission(b);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,12 @@
|
||||||
package org.baseband.launcher.util;
|
/*
|
||||||
|
* Copyright (c) 2023 Jess H & Daniella H. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Unauthorized copying of this file via any medium is Strictly Prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.baseband.launcher.util.security;
|
||||||
|
|
||||||
|
import org.baseband.launcher.classloader.CustomClassloader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
@ -11,11 +19,20 @@ import java.util.Vector;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class PermissionManager {
|
public class PermissionManager {
|
||||||
|
|
||||||
public static boolean checkMayAccessClasses(boolean checkCallerIsCL) {
|
public static boolean checkMayAccessClasses(boolean checkCallerIsCL) {
|
||||||
|
|
||||||
|
if(!(System.getSecurityManager() instanceof BaseBandSecurityManager)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
StackTraceElement[] st = Thread.currentThread().getStackTrace();
|
StackTraceElement[] st = Thread.currentThread().getStackTrace();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Set<ClassLoader> uniqueClassLoaders = Thread.getAllStackTraces().keySet().stream()
|
Set<ClassLoader> uniqueClassLoaders = Thread.getAllStackTraces().keySet().stream()
|
||||||
.map(thread -> thread.getContextClassLoader())
|
.map(Thread::getContextClassLoader)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
package org.baseband.launcher.util;
|
/*
|
||||||
|
* Copyright (c) 2023 Jess H & Daniella H. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Unauthorized copying of this file via any medium is Strictly Prohibited.
|
||||||
|
*/
|
||||||
|
|
||||||
import tudbut.obj.DoubleTypedObject;
|
package org.baseband.launcher.util.security;
|
||||||
import tudbut.tools.Lock;
|
|
||||||
|
import org.baseband.launcher.util.Lock;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
// Keeps some data as safe as possible, unable to be accessed even by reflection
|
// Keeps some data as safe as possible, unable to be accessed even by reflection
|
||||||
public class DataKeeper<T> {
|
public class SecureContainer<T> {
|
||||||
public static boolean forgetAll = false;
|
public static boolean forgetAll = false;
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,9 +24,9 @@ public class DataKeeper<T> {
|
||||||
private final boolean checkCallerIsCL;
|
private final boolean checkCallerIsCL;
|
||||||
private final Lock lock = new Lock(true);
|
private final Lock lock = new Lock(true);
|
||||||
private final Queue<DoubleTypedObject<Consumer<Accessor<T>>, Lock>> nextFunctionToRun = new LinkedList<>();
|
private final Queue<DoubleTypedObject<Consumer<Accessor<T>>, Lock>> nextFunctionToRun = new LinkedList<>();
|
||||||
Thread keeper = new Thread(this::keep, "DataKeeper"); { keeper.start(); }
|
Thread keeper = new Thread(this::keep, "SecureContainer"); { keeper.start(); }
|
||||||
|
|
||||||
public DataKeeper(T toKeep, boolean checkCallerIsCL) {
|
public SecureContainer(T toKeep, boolean checkCallerIsCL) {
|
||||||
dataInsertion = () -> toKeep;
|
dataInsertion = () -> toKeep;
|
||||||
this.checkCallerIsCL = checkCallerIsCL;
|
this.checkCallerIsCL = checkCallerIsCL;
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
@ -62,6 +66,26 @@ public class DataKeeper<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class DoubleTypedObject<O, T> {
|
||||||
|
public O o;
|
||||||
|
public T t;
|
||||||
|
|
||||||
|
public DoubleTypedObject(O o, T t) {
|
||||||
|
this.o = o;
|
||||||
|
this.t = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o1) {
|
||||||
|
if (this == o1) return true;
|
||||||
|
if (!(o1 instanceof DoubleTypedObject)) return false;
|
||||||
|
DoubleTypedObject<?, ?> that = (DoubleTypedObject<?, ?>) o1;
|
||||||
|
return Objects.equals(o, that.o) && Objects.equals(t, that.t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A very last, third layer of protection, not actually that necessary.
|
// A very last, third layer of protection, not actually that necessary.
|
||||||
public static class Accessor<T> {
|
public static class Accessor<T> {
|
||||||
// The accessor will only ever be in local variables, so it does
|
// The accessor will only ever be in local variables, so it does
|
Loading…
Add table
Reference in a new issue