From ed00a3778f43629f05aa030aa11e9b3d6f7b5adb Mon Sep 17 00:00:00 2001 From: zaxar163 Date: Sun, 2 Dec 2018 22:15:21 +0300 Subject: [PATCH] ClassWriter hierarchy... --- .../ru/gravit/launchserver/ProguardConf.java | 4 +- .../launchserver/asm/ClassMetadataReader.java | 93 +++++++++++++++++++ .../launchserver/asm/SafeClassWriter.java | 40 ++++++++ .../auth/hwid/AcceptHWIDHandler.java | 1 - .../launchserver/binary/BuildContext.java | 10 +- .../binary/JARLauncherBinary.java | 67 ++++++------- .../launchserver/binary/LauncherBinary.java | 6 +- .../manangers/BuildHookManager.java | 81 +++++++++++----- .../manangers/NodeTransformer.java | 40 ++++++++ 9 files changed, 279 insertions(+), 63 deletions(-) create mode 100644 LaunchServer/src/main/java/ru/gravit/launchserver/asm/ClassMetadataReader.java create mode 100644 LaunchServer/src/main/java/ru/gravit/launchserver/asm/SafeClassWriter.java create mode 100644 LaunchServer/src/main/java/ru/gravit/launchserver/manangers/NodeTransformer.java diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/ProguardConf.java b/LaunchServer/src/main/java/ru/gravit/launchserver/ProguardConf.java index 82ec4992..29e38b60 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/ProguardConf.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/ProguardConf.java @@ -40,8 +40,8 @@ public ProguardConf(LaunchServer srv) { prepare(false); if (srv.config.genMappings) confStrs.add("-printmapping \'" + mappings.toFile().getName() + "\'"); confStrs.add("-obfuscationdictionary \'" + words.toFile().getName() + "\'"); - confStrs.add("-injar \'" + srv.dir.toAbsolutePath() + IOHelper.PLATFORM_SEPARATOR + srv.config.binaryName + ".jar\'"); - confStrs.add("-outjar \'" + srv.dir.toAbsolutePath() + IOHelper.PLATFORM_SEPARATOR + srv.config.binaryName + "-obf.jar\'"); + confStrs.add("-injar \'" + srv.dir.toAbsolutePath() + IOHelper.PLATFORM_SEPARATOR + srv.config.binaryName + "-nonObf.jar\'"); + confStrs.add("-outjar \'" + srv.dir.toAbsolutePath() + IOHelper.PLATFORM_SEPARATOR + srv.config.binaryName + "-obfed.jar\'"); confStrs.add("-classobfuscationdictionary \'" + words.toFile().getName() + "\'"); confStrs.add(readConf()); diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/asm/ClassMetadataReader.java b/LaunchServer/src/main/java/ru/gravit/launchserver/asm/ClassMetadataReader.java new file mode 100644 index 00000000..e26c05a2 --- /dev/null +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/asm/ClassMetadataReader.java @@ -0,0 +1,93 @@ +package ru.gravit.launchserver.asm; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.jar.JarFile; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; + +import ru.gravit.utils.helper.IOHelper; + +/** + * Позволяет искать методы внутри незагруженных классов и общие суперклассы для + * чего угодно. Работает через поиск class-файлов в classpath. + */ +public class ClassMetadataReader { + private class CheckSuperClassVisitor extends ClassVisitor { + + String superClassName; + + public CheckSuperClassVisitor() { + super(Opcodes.ASM5); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, + String[] interfaces) { + superClassName = superName; + } + } + + private final List cp; + + public ClassMetadataReader(List cp) { + this.cp = cp; + } + + public List getCp() { + return cp; + } + + public ClassMetadataReader() { + this.cp = new ArrayList<>(); + } + + public void acceptVisitor(byte[] classData, ClassVisitor visitor) { + new ClassReader(classData).accept(visitor, 0); + } + + public void acceptVisitor(String className, ClassVisitor visitor) throws IOException { + acceptVisitor(getClassData(className), visitor); + } + + public byte[] getClassData(String className) throws IOException { + for (JarFile f : cp) { + if (f.getEntry(className + ".class") != null) try (InputStream in = f.getInputStream(f.getEntry(className + ".class"))) { return IOHelper.read(in); } + } + return IOHelper.read(IOHelper.getResourceURL(className + ".class")); + } + + public String getSuperClass(String type) { + if (type.equals("java/lang/Object")) return null; + try { + return getSuperClassASM(type); + } catch (Exception e) { + return "java/lang/Object"; + } + } + + protected String getSuperClassASM(String type) throws IOException { + CheckSuperClassVisitor cv = new CheckSuperClassVisitor(); + acceptVisitor(type, cv); + return cv.superClassName; + } + + /** + * Возвращает суперклассы в порядке возрастающей конкретности (начиная с + * java/lang/Object и заканчивая данным типом) + */ + public ArrayList getSuperClasses(String type) { + ArrayList superclasses = new ArrayList<>(1); + superclasses.add(type); + while ((type = getSuperClass(type)) != null) + superclasses.add(type); + Collections.reverse(superclasses); + return superclasses; + } + +} diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/asm/SafeClassWriter.java b/LaunchServer/src/main/java/ru/gravit/launchserver/asm/SafeClassWriter.java new file mode 100644 index 00000000..5aa2a11c --- /dev/null +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/asm/SafeClassWriter.java @@ -0,0 +1,40 @@ +package ru.gravit.launchserver.asm; + +import java.util.ArrayList; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; + +/** + * ClassWriter с другой реализацией метода getCommonSuperClass: при его + * использовании не происходит загрузки классов. + */ +public class SafeClassWriter extends ClassWriter { + + private final ClassMetadataReader classMetadataReader; + + public SafeClassWriter(ClassMetadataReader classMetadataReader, int flags) { + super(flags); + this.classMetadataReader = classMetadataReader; + } + + public SafeClassWriter(ClassReader classReader, ClassMetadataReader classMetadataReader, int flags) { + super(classReader, flags); + this.classMetadataReader = classMetadataReader; + } + + @Override + protected String getCommonSuperClass(String type1, String type2) { + ArrayList superClasses1 = classMetadataReader.getSuperClasses(type1); + ArrayList superClasses2 = classMetadataReader.getSuperClasses(type2); + int size = Math.min(superClasses1.size(), superClasses2.size()); + int i; + for (i = 0; i < size && superClasses1.get(i).equals(superClasses2.get(i)); i++) + ; + if (i == 0) + return "java/lang/Object"; + else + return superClasses1.get(i - 1); + } + +} \ No newline at end of file diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/auth/hwid/AcceptHWIDHandler.java b/LaunchServer/src/main/java/ru/gravit/launchserver/auth/hwid/AcceptHWIDHandler.java index 4d277426..5a9802ab 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/auth/hwid/AcceptHWIDHandler.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/auth/hwid/AcceptHWIDHandler.java @@ -1,7 +1,6 @@ package ru.gravit.launchserver.auth.hwid; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import ru.gravit.launcher.HWID; diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/BuildContext.java b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/BuildContext.java index fe597fbb..c8905f15 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/BuildContext.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/BuildContext.java @@ -5,17 +5,19 @@ import java.io.IOException; import java.io.InputStream; import java.util.Set; -import java.util.jar.JarInputStream; import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; public class BuildContext { public final ZipOutputStream output; public final JAConfigurator config; + public final JARLauncherBinary data; - public BuildContext(ZipOutputStream output, JAConfigurator config) { + public BuildContext(ZipOutputStream output, JAConfigurator config, JARLauncherBinary data) { this.output = output; this.config = config; + this.data = data; } public void pushFile(String filename, InputStream inputStream) throws IOException { @@ -24,7 +26,7 @@ public void pushFile(String filename, InputStream inputStream) throws IOExceptio IOHelper.transfer(inputStream, output); } - public void pushJarFile(JarInputStream input) throws IOException { + public void pushJarFile(ZipInputStream input) throws IOException { ZipEntry e = input.getNextEntry(); while (e != null) { output.putNextEntry(e); @@ -33,7 +35,7 @@ public void pushJarFile(JarInputStream input) throws IOException { } } - public void pushJarFile(JarInputStream input, Set blacklist) throws IOException { + public void pushJarFile(ZipInputStream input, Set blacklist) throws IOException { ZipEntry e = input.getNextEntry(); while (e != null) { if (blacklist.contains(e.getName())) { diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java index 0c1e0520..213f20da 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; +import java.util.jar.JarFile; import java.util.Map.Entry; import java.util.zip.ZipEntry; import java.util.zip.ZipException; @@ -22,13 +23,15 @@ import ru.gravit.launcher.Launcher; import ru.gravit.launcher.LauncherConfig; import ru.gravit.utils.helper.CommonHelper; -import ru.gravit.utils.helper.EnvHelper; import ru.gravit.utils.helper.IOHelper; import ru.gravit.utils.helper.LogHelper; import ru.gravit.utils.helper.SecurityHelper; import ru.gravit.utils.helper.SecurityHelper.DigestAlgorithm; +import ru.gravit.utils.helper.UnpackHelper; import ru.gravit.launcher.serialize.HOutput; import ru.gravit.launchserver.LaunchServer; +import ru.gravit.launchserver.asm.ClassMetadataReader; +import ru.gravit.launchserver.manangers.BuildHookManager.ZipBuildHook; import proguard.Configuration; import proguard.ConfigurationParser; import proguard.ParseException; @@ -36,8 +39,6 @@ public final class JARLauncherBinary extends LauncherBinary { - public static final String[] guardFileList = {"Avanguard64.dll", "Avanguard32.dll", "wrapper64.exe", "wrapper32.exe"}; - private final class RuntimeDirVisitor extends SimpleFileVisitor { private final ZipOutputStream output; private final Map runtime; @@ -68,7 +69,8 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO } } - private final class GuardDirVisitor extends SimpleFileVisitor { + @SuppressWarnings("unused") + private final class GuardDirVisitor extends SimpleFileVisitor { private final ZipOutputStream output; private final Map guard; @@ -106,25 +108,28 @@ private static ZipEntry newGuardEntry(String fileName) { return newZipEntry(Launcher.GUARD_DIR + IOHelper.CROSS_SEPARATOR + fileName); } - + public final Path cleanJar; public final Path runtimeDir; public final Path guardDir; - - public final Path initScriptFile; - - public final Path obfJar; - - + public final Path obfOutJar; + public ClassMetadataReader reader; + public JARLauncherBinary(LaunchServer server) throws IOException { - super(server, server.dir.resolve(server.config.binaryName + ".jar"), - server.dir.resolve(server.config.binaryName + "-obf.jar")); + super(server, server.dir.resolve(server.config.binaryName + "-nonObf.jar"), + server.dir.resolve(server.config.binaryName + ".jar")); runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR); - guardDir = server.dir.resolve("guard"); + guardDir = server.dir.resolve(Launcher.GUARD_DIR); initScriptFile = runtimeDir.resolve(Launcher.INIT_SCRIPT_FILE); - obfJar = syncBinaryFile; + obfJar = server.dir.resolve(server.config.binaryName + "-obfed.jar"); + obfOutJar = server.config.buildPostTransform.enabled ? server.dir.resolve(server.config.binaryName + "-obf.jar") : syncBinaryFile; + cleanJar = server.dir.resolve(server.config.binaryName + "-clean.jar"); + reader = new ClassMetadataReader(); + UnpackHelper.unpack(IOHelper.getResourceURL("Launcher.jar"), cleanJar); + reader.getCp().add(new JarFile(cleanJar.toFile())); tryUnpackRuntime(); + tryUnpackGuard(); } @Override @@ -148,13 +153,10 @@ public void build() throws IOException { } catch (ParseException e1) { e1.printStackTrace(); } + for (Runnable r : server.buildHookManager.getPostProguardRunHooks()) r.run(); if (server.buildHookManager.isNeedPostProguardHook()) { - Path obfPath = Paths.get(server.config.binaryName + "-obf.jar"); - Path tmpPath = Paths.get(server.config.binaryName + "-tmp.jar"); - IOHelper.move(obfPath, tmpPath); - try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(obfPath))) { - try (ZipInputStream input = new ZipInputStream( - IOHelper.newInput(tmpPath))) { + try (ZipInputStream input = new ZipInputStream( + IOHelper.newInput(obfJar)); ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(obfOutJar))) { ZipEntry e = input.getNextEntry(); while (e != null) { String filename = e.getName(); @@ -167,23 +169,25 @@ public void build() throws IOException { IOHelper.transfer(input, outputStream); bytes = outputStream.toByteArray(); } - bytes = server.buildHookManager.proGuardClassTransform(bytes, classname); + bytes = server.buildHookManager.proGuardClassTransform(bytes, classname, this); try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) { IOHelper.transfer(inputStream, output); } } else IOHelper.transfer(input, output); - e = input.getNextEntry(); + e = input.getNextEntry(); } - } + for (ZipBuildHook h : server.buildHookManager.getProguardBuildHooks()) h.build(output); } + } else { + IOHelper.move(obfJar, obfOutJar); } - //if (server.config.buildPostTransform.enabled) - // transformedBuild(); + if (server.config.buildPostTransform.enabled) + transformedBuild(); } private void transformedBuild() throws IOException { - String cmd = CommonHelper.replace(server.config.buildPostTransform.script, "launcher-output", IOHelper.toAbsPathString(syncBinaryFile), "launcher-obf", IOHelper.toAbsPathString(obfJar), "launcher-nonObf", IOHelper.toAbsPathString(binaryFile)); + String cmd = CommonHelper.replace(server.config.buildPostTransform.script, "launcher-output", IOHelper.toAbsPathString(syncBinaryFile), "launcher-obf", IOHelper.toAbsPathString(obfOutJar), "launcher-nonObf", IOHelper.toAbsPathString(binaryFile)); ProcessBuilder builder = new ProcessBuilder(); builder.directory(IOHelper.toAbsPath(server.dir).toFile()); builder.inheritIO(); @@ -203,7 +207,7 @@ private void transformedBuild() throws IOException { private void stdBuild() throws IOException { try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(binaryFile)); JAConfigurator jaConfigurator = new JAConfigurator(AutogenConfig.class)) { - BuildContext context = new BuildContext(output, jaConfigurator); + BuildContext context = new BuildContext(output, jaConfigurator, this); server.buildHookManager.preHook(context); jaConfigurator.setAddress(server.config.getAddress()); jaConfigurator.setPort(server.config.port); @@ -214,7 +218,7 @@ private void stdBuild() throws IOException { jaConfigurator.setDownloadJava(server.config.isDownloadJava); server.buildHookManager.registerAllClientModuleClass(jaConfigurator); try (ZipInputStream input = new ZipInputStream( - IOHelper.newInput(IOHelper.getResourceURL("Launcher.jar")))) { + IOHelper.newInput(cleanJar))) { ZipEntry e = input.getNextEntry(); while (e != null) { String filename = e.getName(); @@ -237,20 +241,19 @@ private void stdBuild() throws IOException { IOHelper.transfer(input, outputStream); bytes = outputStream.toByteArray(); } - bytes = server.buildHookManager.classTransform(bytes, classname); + bytes = server.buildHookManager.classTransform(bytes, classname, this); try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) { IOHelper.transfer(inputStream, output); } } else IOHelper.transfer(input, output); - // } e = input.getNextEntry(); } } // write additional classes for (Entry ent : server.buildHookManager.getIncludeClass().entrySet()) { output.putNextEntry(newZipEntry(ent.getKey().replace('.', '/').concat(".class"))); - output.write(server.buildHookManager.classTransform(ent.getValue(), ent.getKey())); + output.write(server.buildHookManager.classTransform(ent.getValue(), ent.getKey(), this)); } // map for guard Map runtime = new HashMap<>(256); diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/LauncherBinary.java b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/LauncherBinary.java index 508bfe8c..5464450e 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/LauncherBinary.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/LauncherBinary.java @@ -10,10 +10,10 @@ public abstract class LauncherBinary { - protected final LaunchServer server; + public final LaunchServer server; - protected final Path binaryFile; - protected final Path syncBinaryFile; + public final Path binaryFile; + public final Path syncBinaryFile; private volatile DigestBytesHolder binary; private volatile byte[] sign; diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/manangers/BuildHookManager.java b/LaunchServer/src/main/java/ru/gravit/launchserver/manangers/BuildHookManager.java index d693bd16..e52d6a18 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/manangers/BuildHookManager.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/manangers/BuildHookManager.java @@ -4,41 +4,49 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.zip.ZipOutputStream; import ru.gravit.launcher.AutogenConfig; import ru.gravit.launcher.modules.TestClientModule; import ru.gravit.launchserver.binary.BuildContext; import ru.gravit.launchserver.binary.JAConfigurator; +import ru.gravit.launchserver.binary.JARLauncherBinary; public class BuildHookManager { @FunctionalInterface - public interface PostBuildHook { + public static interface ZipBuildHook { + void build(ZipOutputStream context); + } + + @FunctionalInterface + public static interface BuildHook { void build(BuildContext context); } @FunctionalInterface - public interface PreBuildHook { - void build(BuildContext context); - } - - @FunctionalInterface - public interface Transformer { - byte[] transform(byte[] input, CharSequence classname); + public static interface Transformer { + byte[] transform(byte[] input, CharSequence classname, JARLauncherBinary data); } private boolean BUILDRUNTIME; - private final Set POST_HOOKS; + private final Set POST_HOOKS; + private final Set POST_PROGUARDRUN_HOOKS; private final Set POST_PROGUARD_HOOKS; - private final Set PRE_HOOKS; + private final Set PRE_HOOKS; + private final Set POST_PROGUARD_BUILDHOOKS; private final Set CLASS_TRANSFORMER; private final Set CLASS_BLACKLIST; private final Set MODULE_CLASS; private final Map INCLUDE_CLASS; + private final NodeTransformer noder; + private final NodeTransformer proguardNoder; public BuildHookManager() { POST_HOOKS = new HashSet<>(4); + POST_PROGUARDRUN_HOOKS = new HashSet<>(4); POST_PROGUARD_HOOKS = new HashSet<>(4); PRE_HOOKS = new HashSet<>(4); + POST_PROGUARD_BUILDHOOKS = new HashSet<>(4); CLASS_BLACKLIST = new HashSet<>(4); MODULE_CLASS = new HashSet<>(4); INCLUDE_CLASS = new HashMap<>(4); @@ -49,9 +57,37 @@ public BuildHookManager() { registerIgnoredClass("META-INF/LICENSE"); registerIgnoredClass("META-INF/NOTICE"); registerClientModuleClass(TestClientModule.class.getName()); + noder = new NodeTransformer(); + registerClassTransformer(noder); + proguardNoder = new NodeTransformer(); + registerProGuardHook(proguardNoder); } - public void autoRegisterIgnoredClass(String clazz) { + public NodeTransformer getProguardNoder() { + return proguardNoder; + } + + public NodeTransformer getNoder() { + return noder; + } + + public Set getProguardBuildHooks() { + return POST_PROGUARD_BUILDHOOKS; + } + + public Set getPostProguardRunHooks() { + return POST_PROGUARDRUN_HOOKS; + } + + public void addPostProguardRunHook(Runnable hook) { + POST_PROGUARDRUN_HOOKS.add(hook); + } + + public void addPostProguardRunHook(ZipBuildHook hook) { + POST_PROGUARD_BUILDHOOKS.add(hook); + } + + public void autoRegisterIgnoredClass(String clazz) { CLASS_BLACKLIST.add(clazz.replace('.', '/').concat(".class")); } @@ -59,15 +95,15 @@ public boolean buildRuntime() { return BUILDRUNTIME; } - public byte[] classTransform(byte[] clazz, CharSequence classname) { + public byte[] classTransform(byte[] clazz, CharSequence classname, JARLauncherBinary reader) { byte[] result = clazz; - for (Transformer transformer : CLASS_TRANSFORMER) result = transformer.transform(result, classname); + for (Transformer transformer : CLASS_TRANSFORMER) result = transformer.transform(result, classname, reader); return result; } - public byte[] proGuardClassTransform(byte[] clazz, CharSequence classname) { + public byte[] proGuardClassTransform(byte[] clazz, CharSequence classname, JARLauncherBinary reader) { byte[] result = clazz; - for (Transformer transformer : POST_PROGUARD_HOOKS) result = transformer.transform(result, classname); + for (Transformer transformer : POST_PROGUARD_HOOKS) result = transformer.transform(result, classname, reader); return result; } @@ -80,15 +116,18 @@ public Map getIncludeClass() { } public boolean isContainsBlacklist(String clazz) { - return CLASS_BLACKLIST.contains(clazz); + for (String classB : CLASS_BLACKLIST) { + if (clazz.startsWith(classB)) return true; + } + return false; } public void postHook(BuildContext context) { - for (PostBuildHook hook : POST_HOOKS) hook.build(context); + for (BuildHook hook : POST_HOOKS) hook.build(context); } public void preHook(BuildContext context) { - for (PreBuildHook hook : PRE_HOOKS) hook.build(context); + for (BuildHook hook : PRE_HOOKS) hook.build(context); } public void registerAllClientModuleClass(JAConfigurator cfg) { @@ -107,7 +146,7 @@ public void registerIgnoredClass(String clazz) { CLASS_BLACKLIST.add(clazz); } - public void registerPostHook(PostBuildHook hook) { + public void registerPostHook(BuildHook hook) { POST_HOOKS.add(hook); } @@ -116,10 +155,10 @@ public void registerProGuardHook(Transformer hook) { } public boolean isNeedPostProguardHook() { - return !POST_PROGUARD_HOOKS.isEmpty(); + return POST_PROGUARD_HOOKS.size() > 1 || !POST_PROGUARDRUN_HOOKS.isEmpty() || !POST_PROGUARD_BUILDHOOKS.isEmpty() || !proguardNoder.getTransLst().isEmpty(); } - public void registerPreHook(PreBuildHook hook) { + public void registerPreHook(BuildHook hook) { PRE_HOOKS.add(hook); } diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/manangers/NodeTransformer.java b/LaunchServer/src/main/java/ru/gravit/launchserver/manangers/NodeTransformer.java new file mode 100644 index 00000000..321a0b88 --- /dev/null +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/manangers/NodeTransformer.java @@ -0,0 +1,40 @@ +package ru.gravit.launchserver.manangers; + +import java.util.ArrayList; +import java.util.List; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; + +import ru.gravit.launchserver.asm.SafeClassWriter; +import ru.gravit.launchserver.binary.JARLauncherBinary; +import ru.gravit.launchserver.manangers.BuildHookManager.Transformer; + +public class NodeTransformer implements Transformer { + @FunctionalInterface + public static interface ClassNodeTransformer { + void transform(ClassNode node, CharSequence classname, JARLauncherBinary data); + } + + private final List transLst; + + public List getTransLst() { + return transLst; + } + + public NodeTransformer() { + transLst = new ArrayList<>(); + } + + @Override + public byte[] transform(byte[] input, CharSequence classname, JARLauncherBinary data) { + ClassReader cr = new ClassReader(input); + ClassNode cn = new ClassNode(); + cr.accept(cn, ClassReader.EXPAND_FRAMES); + for (ClassNodeTransformer tr : transLst) tr.transform(cn, classname, data); + ClassWriter cw = new SafeClassWriter(data.reader, ClassWriter.COMPUTE_MAXS); + cn.accept(cw); + return cw.toByteArray(); + } +} \ No newline at end of file