Skip to content
Merged

dev #142

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ idea {
}
}

version = "2.6.1"
version = "2.6.2-SNAPSHOT"

tasks.register("publishAllToMavenCentral") {
dependsOn(":memshell-party-common:publishToMavenCentral")
Expand Down
3 changes: 3 additions & 0 deletions generator/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ dependencies {
implementation(libs.jakarta.servlet.api)
implementation(libs.spring.webmvc)
implementation(libs.spring.webflux)
implementation(libs.tomcat.embed.core)
implementation(libs.reactor.netty.core)
implementation(libs.alibaba.dubbo)
implementation(libs.apache.dubbo)
implementation(libs.jackson.annotations)
implementation(libs.bundles.jna)

Expand Down
1 change: 1 addition & 0 deletions generator/src/main/java/com/reajason/javaweb/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ public class Server {
public static final String SpringWebFlux = "SpringWebFlux";
public static final String XXLJOB = "XXLJOB";
public static final String Struct2 = "Struct2";
public static final String Dubbo = "Dubbo";
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.reajason.javaweb.memshell;

import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.asm.ClassInterfaceUtils;
import com.reajason.javaweb.memshell.config.InjectorConfig;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.DubboServiceInterfaceHelperGenerator;
import com.reajason.javaweb.memshell.generator.InjectorGenerator;
import com.reajason.javaweb.memshell.generator.WebSocketByPassHelperGenerator;
import com.reajason.javaweb.memshell.server.AbstractServer;
Expand All @@ -15,6 +17,7 @@
import com.reajason.javaweb.utils.CommonUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.apache.commons.lang3.tuple.Pair;

import java.util.Map;
Expand Down Expand Up @@ -60,20 +63,36 @@ public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig in

byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig);

injectorConfig.setInjectorClass(injectorClass);
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
injectorConfig.setShellClassBytes(shellBytes);
if (shellConfig.getShellType().endsWith(ShellType.DUBBO_SERVICE)) {
String packageName = CommonUtil.getPackageName(shellToolConfig.getShellClassName());
String simpleName = CommonUtil.getSimpleName(shellToolConfig.getShellClassName());
String interfaceName = packageName + ".I" + simpleName;
injectorConfig.setInjectorHelperClassName(interfaceName);
injectorConfig.setHelperClassBytes(DubboServiceInterfaceHelperGenerator.getBytes(interfaceName, shellConfig));
shellBytes = ClassInterfaceUtils.addInterface(shellBytes, interfaceName);
String urlPattern = injectorConfig.getUrlPattern();
if (Strings.CS.equalsAny(urlPattern, "/*", "/")
|| StringUtils.isBlank(urlPattern)) {
injectorConfig.setUrlPattern(interfaceName);
}
}

if (ShellType.BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())
|| ShellType.JAKARTA_BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())) {
injectorConfig.setHelperClassBytes(WebSocketByPassHelperGenerator.getBytes(shellConfig, shellToolConfig));
String helperClassName = shellToolConfig.getShellClassName() + "$1";
injectorConfig.setInjectorHelperClassName(helperClassName);
injectorConfig.setHelperClassBytes(WebSocketByPassHelperGenerator.getBytes(helperClassName, shellConfig, shellToolConfig));
}

injectorConfig.setInjectorClass(injectorClass);
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
injectorConfig.setShellClassBytes(shellBytes);

InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
byte[] injectorBytes = injectorGenerator.generate();
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
ProbeConfig probeConfig = ProbeConfig.builder()
.shellClassName(injectorConfig.getInjectorClassName() + "1")
.shellClassName(injectorConfig.getInjectorClassName() + "Wrapper")
.probeMethod(ProbeMethod.ResponseBody)
.probeContent(ProbeContent.Bytecode)
.targetJreVersion(shellConfig.getTargetJreVersion())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class ServerFactory {
register(Server.SpringWebFlux, SpringWebFlux::new);
register(Server.XXLJOB, XxlJob::new);
register(Server.Struct2, Struct2::new);
register(Server.Dubbo, Dubbo::new);

addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
.addShellClass(SERVLET, GodzillaServlet.class)
Expand Down Expand Up @@ -162,6 +163,8 @@ public class ServerFactory {
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
.addShellClass(ACTION, CommandStruct2Action.class)
.addShellClass(ALIBABA_DUBBO_SERVICE, CommandDubboService.class)
.addShellClass(APACHE_DUBBO_SERVICE, CommandDubboService.class)
.build());

addToolMapping(ShellTool.Suo5, ToolMapping.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@ public class ShellType {
public static final String JAKARTA_BYPASS_NGINX_WEBSOCKET = "JakartaWebBypassNginx" + WEBSOCKET;

public static final String ACTION = "Action";

public static final String DUBBO_SERVICE = "DubboService";
public static final String APACHE_DUBBO_SERVICE = "Apache" + DUBBO_SERVICE;
public static final String ALIBABA_DUBBO_SERVICE = "Alibaba" + DUBBO_SERVICE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,15 @@ public static ImplementationClass fromString(String encryptor) {
}

public enum Encryptor {
RAW, DOUBLE_BASE64;
RAW, BASE64, DOUBLE_BASE64;

public static Encryptor fromString(String encryptor) {
if (encryptor != null && encryptor.equals("DOUBLE_BASE64")) {
return DOUBLE_BASE64;
}
if (encryptor != null && encryptor.equals("BASE64")) {
return BASE64;
}
return RAW;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public class InjectorConfig {
@Builder.Default
private String injectorClassName = CommonUtil.generateInjectorClassName();

/**
* 辅助类类名
*/
private String injectorHelperClassName;


/**
* 注入访问的地址
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.reajason.javaweb.memshell.generator;

import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.shelltool.ShellDubboService;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;

public class DubboServiceInterfaceHelperGenerator {
public static byte[] getBytes(String interfaceName, ShellConfig shellConfig) {
try (DynamicType.Unloaded<ShellDubboService> make = new ByteBuddy()
.redefine(ShellDubboService.class)
.name(interfaceName)
.make()) {
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.memshell.config.*;
import com.reajason.javaweb.memshell.shelltool.wsbypass.TomcatWsBypassValve;
import com.reajason.javaweb.utils.CommonUtil;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import org.apache.commons.lang3.tuple.Pair;
Expand All @@ -19,7 +18,7 @@
* @since 2026/1/13
*/
public class WebSocketByPassHelperGenerator {
public static byte[] getBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
public static byte[] getBytes(String helperClassName, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
Pair<String, String> headerPair = getHeaderPair(shellToolConfig);
if (headerPair == null) {
throw new GenerationException("unsupported shell config: " + shellConfig.getShellTool());
Expand All @@ -31,7 +30,7 @@ public static byte[] getBytes(ShellConfig shellConfig, ShellToolConfig shellTool
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
.field(named("headerName")).value(headerPair.getKey())
.field(named("headerValue")).value(headerPair.getValue())
.name(CommonUtil.generateClassName());
.name(helperClassName);
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.reajason.javaweb.memshell.generator.command;

import com.reajason.javaweb.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice;

/**
* @author ReaJason
* @since 2025/4/27
*/
public class Base64ParamInterceptor {

@Advice.OnMethodExit
public static void enter(@Advice.Argument(value = 0) String param, @Advice.Return(readOnly = false) String returnValue) throws Exception {
returnValue = ShellCommonUtil.base64DecodeToString(param);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ public DynamicType.Builder<?> getBuilder() {
.visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString")))
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
}
if (CommandConfig.Encryptor.BASE64.equals(shellToolConfig.getEncryptor())) {
builder = builder
.visit(MethodCallReplaceVisitorWrapper.newInstance("getParam",
shellToolConfig.getShellClassName(), ShellCommonUtil.class.getName()))
.defineMethod("base64DecodeToString", String.class, Visibility.PUBLIC, Ownership.STATIC)
.withParameters(String.class)
.throwing(Exception.class)
.intercept(FixedValue.nullValue())
.visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString")))
.visit(Advice.to(Base64ParamInterceptor.class).on(named("getParam")));
}
if (CommandConfig.ImplementationClass.RuntimeExec.equals(shellToolConfig.getImplementationClass())) {
builder = builder.visit(Advice.withCustomMapping()
.bind(TemplateAnnotation.class, shellToolConfig.getTemplate())
Expand Down
Loading
Loading