From c9f4bf715e4021a662ea0a4cd065f306e588623c Mon Sep 17 00:00:00 2001 From: Zaxar163 Date: Sun, 7 Apr 2019 07:32:32 +0300 Subject: [PATCH] =?UTF-8?q?[FEATURE]=20LauncherAgent=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B5=D0=BB=D0=B0=D0=BD.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Launcher/build.gradle | 1 + .../ru/gravit/launcher/LauncherAgent.java | 159 ++++++++++++++++++ .../launcher/client/FunctionalBridge.java | 1 - .../ru/gravit/launcher/LauncherAgent.java | 32 ---- 4 files changed, 160 insertions(+), 33 deletions(-) create mode 100644 Launcher/src/main/java/ru/gravit/launcher/LauncherAgent.java delete mode 100644 libLauncher/src/main/java/ru/gravit/launcher/LauncherAgent.java diff --git a/Launcher/build.gradle b/Launcher/build.gradle index a5f72937..f15b639d 100644 --- a/Launcher/build.gradle +++ b/Launcher/build.gradle @@ -28,6 +28,7 @@ dependencies { pack project(':LauncherAPI') // Not error on obf. bundle 'com.github.oshi:oshi-core:3.13.0' + bundle 'org.ow2.asm:asm-tree:7.1' } task genRuntimeJS(type: Zip) { diff --git a/Launcher/src/main/java/ru/gravit/launcher/LauncherAgent.java b/Launcher/src/main/java/ru/gravit/launcher/LauncherAgent.java new file mode 100644 index 00000000..3a589a16 --- /dev/null +++ b/Launcher/src/main/java/ru/gravit/launcher/LauncherAgent.java @@ -0,0 +1,159 @@ +package ru.gravit.launcher; + +import ru.gravit.utils.helper.LogHelper; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.instrument.Instrumentation; +import java.util.jar.JarFile; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodNode; + +import static org.objectweb.asm.Opcodes.*; + +@LauncherAPI +public final class LauncherAgent { + private static boolean isAgentStarted = false; + public static Instrumentation inst; + + public static void addJVMClassPath(String path) throws IOException { + LogHelper.debug("Launcher Agent addJVMClassPath"); + inst.appendToSystemClassLoaderSearch(new JarFile(path)); + } + + public boolean isAgentStarted() { + return isAgentStarted; + } + + public static void premain(String agentArgument, Instrumentation instrumentation) { + System.out.println("Launcher Agent"); + inst = instrumentation; + isAgentStarted = true; + boolean pb = true; + boolean rt = true; + if (agentArgument != null) { + String trimmedArg = agentArgument.trim(); + if (!trimmedArg.isEmpty()) { + if (trimmedArg.contains("p")) pb = false; + if (trimmedArg.contains("r")) rt = false; + } + } + replaceClasses(pb, rt); + } + + public static boolean isStarted() { + return isAgentStarted; + } + + /** + * @author https://github.com/Konloch/JVM-Sandbox + * Replaces the Runtime class via instrumentation, transforms the class via ASM + */ + public static void replaceClasses(boolean pb, boolean rt) { + for(Class c : inst.getAllLoadedClasses()) { + if(rt && c.getName().equals("java.lang.Runtime")) { + try { + inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.Runtime.class, transformClass(c.getName(), getClassFile(c)))); + } catch(Exception e) { + e.printStackTrace(); + } + } + if(pb && c.getName().equals("java.lang.ProcessBuilder")) { + try { + inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.ProcessBuilder.class, transformClass(c.getName(), getClassFile(c)))); + } catch(Exception e) { + e.printStackTrace(); + } + } + if(c.getName().equals("java.awt.Robot")) { + try { + inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.ProcessBuilder.class, transformClass(c.getName(), getClassFile(c)))); + } catch(Exception e) { + e.printStackTrace(); + } + } + } + } + + /** + * @author https://github.com/Konloch/JVM-Sandbox + * Use ASM to modify the byte array + */ + public static byte[] transformClass(String className, byte[] classBytes) { + if (className.equals("java.lang.Runtime")) { + ClassReader cr=new ClassReader(classBytes); + ClassNode cn=new ClassNode(); + cr.accept(cn,ClassReader.EXPAND_FRAMES); + + for (Object o : cn.methods.toArray()) { + MethodNode m = (MethodNode) o; + if(m.name.equals("exec")) { + m.instructions.insert(new InsnNode(ARETURN)); + m.instructions.insert(new InsnNode(ACONST_NULL)); + } + } + ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + cn.accept(cw); + return cw.toByteArray(); + } else if (className.equals("java.lang.ProcessBuilder")) { + ClassReader cr=new ClassReader(classBytes); + ClassNode cn=new ClassNode(); + cr.accept(cn,ClassReader.EXPAND_FRAMES); + + for (Object o : cn.methods.toArray()) { + MethodNode m = (MethodNode) o; + if(m.name.equals("start")) { + m.instructions.insert(new InsnNode(ARETURN)); + m.instructions.insert(new InsnNode(ACONST_NULL)); + } + } + ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + cn.accept(cw); + return cw.toByteArray(); + } else if (className.equals("java.awt.Robot")) { + ClassReader cr=new ClassReader(classBytes); + ClassNode cn=new ClassNode(); + cr.accept(cn,ClassReader.EXPAND_FRAMES); + + for (Object o : cn.methods.toArray()) { + MethodNode m = (MethodNode) o; + if( m.name.equals("createScreenCapture") || m.name.equals("getPixelColor") || + m.name.equals("keyPress") || m.name.equals("keyRelease") || + m.name.equals("mouseMove") || m.name.equals("mousePress") || + m.name.equals("mouseWheel")) + { + m.instructions.insert(new InsnNode(ARETURN)); + m.instructions.insert(new InsnNode(ACONST_NULL)); + } + } + ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + cn.accept(cw); + return cw.toByteArray(); + } + return classBytes; + } + + /** + * @author https://github.com/Konloch/JVM-Sandbox + * Do not remove this method. Do not to cause classloading! + * Grab the byte array from the loaded Class object + * @param clazz + * @return array, respending this class in bytecode. + * @throws IOException + */ + public static byte[] getClassFile(Class clazz) throws IOException { + InputStream is = clazz.getResourceAsStream( "/" + clazz.getName().replace('.', '/') + ".class"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int r = 0; + byte[] buffer = new byte[8192]; + while((r=is.read(buffer))>=0) { + baos.write(buffer, 0, r); + } + return baos.toByteArray(); + } +} diff --git a/Launcher/src/main/java/ru/gravit/launcher/client/FunctionalBridge.java b/Launcher/src/main/java/ru/gravit/launcher/client/FunctionalBridge.java index d6e1ee5b..6c2e1ba9 100644 --- a/Launcher/src/main/java/ru/gravit/launcher/client/FunctionalBridge.java +++ b/Launcher/src/main/java/ru/gravit/launcher/client/FunctionalBridge.java @@ -14,7 +14,6 @@ import ru.gravit.launcher.request.websockets.RequestInterface; import ru.gravit.launcher.serialize.signed.SignedObjectHolder; -import java.io.IOException; import java.nio.file.Path; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; diff --git a/libLauncher/src/main/java/ru/gravit/launcher/LauncherAgent.java b/libLauncher/src/main/java/ru/gravit/launcher/LauncherAgent.java deleted file mode 100644 index 8c94c604..00000000 --- a/libLauncher/src/main/java/ru/gravit/launcher/LauncherAgent.java +++ /dev/null @@ -1,32 +0,0 @@ -package ru.gravit.launcher; - -import ru.gravit.utils.helper.LogHelper; - -import java.io.IOException; -import java.lang.instrument.Instrumentation; -import java.util.jar.JarFile; - -@LauncherAPI -public final class LauncherAgent { - private static boolean isAgentStarted = false; - public static Instrumentation inst; - - public static void addJVMClassPath(String path) throws IOException { - LogHelper.debug("Launcher Agent addJVMClassPath"); - inst.appendToSystemClassLoaderSearch(new JarFile(path)); - } - - public boolean isAgentStarted() { - return isAgentStarted; - } - - public static void premain(String agentArgument, Instrumentation instrumentation) { - System.out.println("Launcher Agent"); - inst = instrumentation; - isAgentStarted = true; - } - - public static boolean isStarted() { - return isAgentStarted; - } -}