From 70002287e4bedfbc637199742fd55ec0b4d2b4fc Mon Sep 17 00:00:00 2001 From: ThatGamerBlue Date: Sun, 30 Jul 2023 00:28:45 +0100 Subject: [PATCH] feat(scanallclasses): create a scan all classes boolean Not perf tested, shouldn't be too slow though. By default only allows classes globally allowed in the config. Not functional under modlauncher, couldn't see a way to get the transformer to indiscriminately apply to every class loaded. Wasn't sure if I should've added filtering to not process java.* classes, but theoretically these are exploitable so I decided to leave them filtered, might be a bad choice. --- .../agent/SIBTransformer.java | 7 ++++--- .../serializationisbad/core/Patches.java | 21 ++++++++++++++++++- .../core/config/PatchModule.java | 2 ++ .../core/config/SIBConfig.java | 10 +++++++++ .../legacyforge/SIBTransformer.java | 7 ++++--- serializationisbad.json | 1 + 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/agent/src/main/java/io/dogboy/serializationisbad/agent/SIBTransformer.java b/agent/src/main/java/io/dogboy/serializationisbad/agent/SIBTransformer.java index fd1e571..ac71e77 100644 --- a/agent/src/main/java/io/dogboy/serializationisbad/agent/SIBTransformer.java +++ b/agent/src/main/java/io/dogboy/serializationisbad/agent/SIBTransformer.java @@ -2,6 +2,7 @@ import io.dogboy.serializationisbad.core.Patches; import io.dogboy.serializationisbad.core.SerializationIsBad; +import io.dogboy.serializationisbad.core.config.PatchModule; import org.objectweb.asm.tree.ClassNode; import java.lang.instrument.ClassFileTransformer; @@ -13,9 +14,9 @@ public class SIBTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { String classNameDots = className.replace('/', '.'); - if (Patches.getPatchModuleForClass(classNameDots) == null) return classfileBuffer; - - SerializationIsBad.logger.info("Applying patches to " + classNameDots); + if (!Patches.shouldPatchClass(classNameDots)) { + return classfileBuffer; + } ClassNode classNode = Patches.readClassNode(classfileBuffer); Patches.applyPatches(classNameDots, classNode); diff --git a/core/src/main/java/io/dogboy/serializationisbad/core/Patches.java b/core/src/main/java/io/dogboy/serializationisbad/core/Patches.java index 29490ae..974ca6b 100644 --- a/core/src/main/java/io/dogboy/serializationisbad/core/Patches.java +++ b/core/src/main/java/io/dogboy/serializationisbad/core/Patches.java @@ -14,6 +14,14 @@ public class Patches { + public static boolean shouldPatchClass(String className) { + return SerializationIsBad.getInstance().getConfig().isScanAllClasses() || isClassKnown(className); + } + + public static boolean isClassKnown(String className) { + return getPatchModuleForClass(className) != PatchModule.EMPTY; + } + public static PatchModule getPatchModuleForClass(String className) { for (PatchModule patchModule : SerializationIsBad.getInstance().getConfig().getPatchModules()) { if (patchModule.getClassesToPatch().contains(className)) { @@ -21,7 +29,7 @@ public static PatchModule getPatchModuleForClass(String className) { } } - return null; + return PatchModule.EMPTY; } public static ClassNode readClassNode(byte[] classBytecode) { @@ -38,6 +46,13 @@ public static byte[] writeClassNode(ClassNode classNode) { } public static void applyPatches(String className, ClassNode classNode) { + boolean isClassKnown = isClassKnown(className); + boolean patched = false; + + if (isClassKnown) { + SerializationIsBad.logger.info("Applying patches to " + className); + } + for (MethodNode methodNode : classNode.methods) { InsnList instructions = methodNode.instructions; for (int i = 0; i < instructions.size(); i++) { @@ -61,9 +76,13 @@ public static void applyPatches(String className, ClassNode classNode) { instructions.insertBefore(instruction, additionalInstructions); SerializationIsBad.logger.info(" (2/2) Redirecting ObjectInputStream to ClassFilteringObjectInputStream in method " + methodNode.name); + patched = true; } } } + if (patched && !isClassKnown) { + SerializationIsBad.logger.warn("Applied ObjectInputStream patches in unknown class " + className + ", please report this to the developers of SerializationIsBad responsibly."); + } } } diff --git a/core/src/main/java/io/dogboy/serializationisbad/core/config/PatchModule.java b/core/src/main/java/io/dogboy/serializationisbad/core/config/PatchModule.java index f5500b2..4bd4ddd 100644 --- a/core/src/main/java/io/dogboy/serializationisbad/core/config/PatchModule.java +++ b/core/src/main/java/io/dogboy/serializationisbad/core/config/PatchModule.java @@ -4,6 +4,8 @@ import java.util.Set; public class PatchModule { + public final static PatchModule EMPTY = new PatchModule(); + private Set classesToPatch; private Set classAllowlist; private Set packageAllowlist; diff --git a/core/src/main/java/io/dogboy/serializationisbad/core/config/SIBConfig.java b/core/src/main/java/io/dogboy/serializationisbad/core/config/SIBConfig.java index d29f338..c550ece 100644 --- a/core/src/main/java/io/dogboy/serializationisbad/core/config/SIBConfig.java +++ b/core/src/main/java/io/dogboy/serializationisbad/core/config/SIBConfig.java @@ -6,18 +6,28 @@ import java.util.Set; public class SIBConfig { + private boolean scanAllClasses; private boolean executeBlocking; private List patchModules; private Set classAllowlist; private Set packageAllowlist; public SIBConfig() { + this.scanAllClasses = true; this.executeBlocking = true; this.patchModules = new ArrayList<>(); this.classAllowlist = new HashSet<>(); this.packageAllowlist = new HashSet<>(); } + public boolean isScanAllClasses() { + return this.scanAllClasses; + } + + public void setScanAllClasses(boolean scanAllClasses) { + this.scanAllClasses = scanAllClasses; + } + public boolean isExecuteBlocking() { return this.executeBlocking; } diff --git a/legacyforge/src/main/java/io/dogboy/serializationisbad/legacyforge/SIBTransformer.java b/legacyforge/src/main/java/io/dogboy/serializationisbad/legacyforge/SIBTransformer.java index b82bc3d..1eaabec 100644 --- a/legacyforge/src/main/java/io/dogboy/serializationisbad/legacyforge/SIBTransformer.java +++ b/legacyforge/src/main/java/io/dogboy/serializationisbad/legacyforge/SIBTransformer.java @@ -2,15 +2,16 @@ import io.dogboy.serializationisbad.core.Patches; import io.dogboy.serializationisbad.core.SerializationIsBad; +import io.dogboy.serializationisbad.core.config.PatchModule; import net.minecraft.launchwrapper.IClassTransformer; import org.objectweb.asm.tree.ClassNode; public class SIBTransformer implements IClassTransformer { @Override public byte[] transform(String name, String transformedName, byte[] basicClass) { - if (Patches.getPatchModuleForClass(transformedName) == null) return basicClass; - - SerializationIsBad.logger.info("Applying patches to " + transformedName); + if (!Patches.shouldPatchClass(transformedName)) { + return basicClass; + } ClassNode classNode = Patches.readClassNode(basicClass); Patches.applyPatches(transformedName, classNode); diff --git a/serializationisbad.json b/serializationisbad.json index a696b31..5adb715 100644 --- a/serializationisbad.json +++ b/serializationisbad.json @@ -1,4 +1,5 @@ { + "scanAllClasses": true, "executeBlocking": true, "patchModules": [ {