Skip to content

Commit 45fa50f

Browse files
committed
refactor: simplify shell generator
1 parent 344ab2b commit 45fa50f

File tree

10 files changed

+120
-209
lines changed

10 files changed

+120
-209
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.reajason.javaweb.memshell.generator;
2+
3+
import com.reajason.javaweb.memshell.config.ShellConfig;
4+
import com.reajason.javaweb.memshell.config.ShellToolConfig;
5+
6+
/**
7+
* @author ReaJason
8+
* @since 2025/5/27
9+
*/
10+
public abstract class ASMShellGenerator<T extends ShellToolConfig> implements ShellGenerator {
11+
protected final ShellConfig shellConfig;
12+
protected final T shellToolConfig;
13+
14+
protected ASMShellGenerator(ShellConfig shellConfig, T shellToolConfig) {
15+
this.shellConfig = shellConfig;
16+
this.shellToolConfig = shellToolConfig;
17+
}
18+
}
Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,24 @@
11
package com.reajason.javaweb.memshell.generator;
22

3-
import com.reajason.javaweb.ClassBytesShrink;
4-
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
5-
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
6-
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
73
import com.reajason.javaweb.memshell.config.AntSwordConfig;
84
import com.reajason.javaweb.memshell.config.ShellConfig;
9-
import net.bytebuddy.ByteBuddy;
105
import net.bytebuddy.dynamic.DynamicType;
11-
import org.apache.commons.lang3.StringUtils;
126

137
import static net.bytebuddy.matcher.ElementMatchers.named;
148

159
/**
1610
* @author ReaJason
1711
* @since 2025/02/18
1812
*/
19-
public class AntSwordGenerator {
20-
private final ShellConfig shellConfig;
21-
private final AntSwordConfig antSwordConfig;
22-
23-
public AntSwordGenerator(ShellConfig shellConfig, AntSwordConfig antSwordConfig) {
24-
this.shellConfig = shellConfig;
25-
this.antSwordConfig = antSwordConfig;
26-
}
27-
28-
public DynamicType.Builder<?> getBuilder() {
29-
if (antSwordConfig.getShellClass() == null) {
30-
throw new IllegalArgumentException("antSwordConfig.getClazz() == null");
31-
}
32-
if (StringUtils.isBlank(antSwordConfig.getPass())) {
33-
throw new IllegalArgumentException("antSwordConfig.getPass().isBlank()");
34-
}
35-
DynamicType.Builder<?> builder = new ByteBuddy()
36-
.redefine(antSwordConfig.getShellClass())
37-
.name(antSwordConfig.getShellClassName())
38-
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
39-
40-
if (shellConfig.isJakarta()) {
41-
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
42-
}
43-
44-
if (shellConfig.isDebugOff()) {
45-
builder = LogRemoveMethodVisitor.extend(builder);
46-
}
47-
48-
return builder.field(named("pass")).value(antSwordConfig.getPass())
49-
.field(named("headerName")).value(antSwordConfig.getHeaderName())
50-
.field(named("headerValue")).value(antSwordConfig.getHeaderValue());
13+
public class AntSwordGenerator extends ByteBuddyShellGenerator<AntSwordConfig> {
14+
public AntSwordGenerator(ShellConfig shellConfig, AntSwordConfig shellToolConfig) {
15+
super(shellConfig, shellToolConfig);
5116
}
5217

53-
public byte[] getBytes() {
54-
DynamicType.Builder<?> builder = getBuilder();
55-
try (DynamicType.Unloaded<?> make = builder.make()) {
56-
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
57-
}
18+
@Override
19+
protected DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
20+
return builder.field(named("pass")).value(shellToolConfig.getPass())
21+
.field(named("headerName")).value(shellToolConfig.getHeaderName())
22+
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
5823
}
5924
}
Lines changed: 7 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,25 @@
11
package com.reajason.javaweb.memshell.generator;
22

3-
import com.reajason.javaweb.ClassBytesShrink;
4-
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
5-
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
6-
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
73
import com.reajason.javaweb.memshell.config.BehinderConfig;
84
import com.reajason.javaweb.memshell.config.ShellConfig;
95
import com.reajason.javaweb.memshell.utils.DigestUtils;
10-
import net.bytebuddy.ByteBuddy;
116
import net.bytebuddy.dynamic.DynamicType;
12-
import org.apache.commons.lang3.StringUtils;
137

148
import static net.bytebuddy.matcher.ElementMatchers.named;
159

1610
/**
1711
* @author ReaJason
1812
* @since 2024/12/21
1913
*/
20-
public class BehinderGenerator {
21-
private final ShellConfig shellConfig;
22-
private final BehinderConfig behinderConfig;
23-
24-
public BehinderGenerator(ShellConfig shellConfig, BehinderConfig behinderConfig) {
25-
this.shellConfig = shellConfig;
26-
this.behinderConfig = behinderConfig;
14+
public class BehinderGenerator extends ByteBuddyShellGenerator<BehinderConfig> {
15+
public BehinderGenerator(ShellConfig shellConfig, BehinderConfig shellToolConfig) {
16+
super(shellConfig, shellToolConfig);
2717
}
2818

29-
public DynamicType.Builder<?> getBuilder() {
30-
if (behinderConfig.getShellClass() == null) {
31-
throw new IllegalArgumentException("behinderConfig.getClazz() == null");
32-
}
33-
if (StringUtils.isBlank(behinderConfig.getPass())) {
34-
throw new IllegalArgumentException("behinderConfig.getPass().isBlank()");
35-
}
36-
String md5Key = DigestUtils.md5Hex(behinderConfig.getPass()).substring(0, 16);
37-
38-
DynamicType.Builder<?> builder = new ByteBuddy()
39-
.redefine(behinderConfig.getShellClass())
40-
.name(behinderConfig.getShellClassName())
41-
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
42-
43-
if (shellConfig.isJakarta()) {
44-
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
45-
}
46-
47-
if (shellConfig.isDebugOff()) {
48-
builder = LogRemoveMethodVisitor.extend(builder);
49-
}
50-
19+
public DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
20+
String md5Key = DigestUtils.md5Hex(shellToolConfig.getPass()).substring(0, 16);
5121
return builder.field(named("pass")).value(md5Key)
52-
.field(named("headerName")).value(behinderConfig.getHeaderName())
53-
.field(named("headerValue")).value(behinderConfig.getHeaderValue());
54-
}
55-
56-
public byte[] getBytes() {
57-
DynamicType.Builder<?> builder = getBuilder();
58-
try (DynamicType.Unloaded<?> make = builder.make()) {
59-
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
60-
}
22+
.field(named("headerName")).value(shellToolConfig.getHeaderName())
23+
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
6124
}
6225
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.reajason.javaweb.memshell.generator;
2+
3+
import com.reajason.javaweb.ClassBytesShrink;
4+
import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor;
5+
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
6+
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
7+
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
8+
import com.reajason.javaweb.memshell.config.ShellConfig;
9+
import com.reajason.javaweb.memshell.config.ShellToolConfig;
10+
import net.bytebuddy.ByteBuddy;
11+
import net.bytebuddy.dynamic.DynamicType;
12+
13+
/**
14+
* @author ReaJason
15+
* @since 2025/5/27
16+
*/
17+
public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> implements ShellGenerator {
18+
protected final ShellConfig shellConfig;
19+
protected final T shellToolConfig;
20+
21+
protected ByteBuddyShellGenerator(ShellConfig shellConfig, T shellToolConfig) {
22+
this.shellConfig = shellConfig;
23+
this.shellToolConfig = shellToolConfig;
24+
}
25+
26+
protected abstract DynamicType.Builder<?> build(DynamicType.Builder<?> builder);
27+
28+
@Override
29+
public byte[] getBytes() {
30+
DynamicType.Builder<?> builder = build(new ByteBuddy()
31+
.redefine(shellToolConfig.getShellClass())
32+
.name(shellToolConfig.getShellClassName())
33+
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())));
34+
35+
if (shellConfig.isJakarta()) {
36+
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
37+
}
38+
39+
if (shellConfig.isDebugOff()) {
40+
builder = LogRemoveMethodVisitor.extend(builder);
41+
}
42+
43+
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
44+
return ClassBytesShrink.shrink(unloaded.getBytes(), shellConfig.isShrink());
45+
}
46+
}
47+
}

generator/src/main/java/com/reajason/javaweb/memshell/generator/CustomShellGenerator.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,21 @@
1212
* @author ReaJason
1313
* @since 2025/3/18
1414
*/
15-
public class CustomShellGenerator {
16-
17-
private final ShellConfig shellConfig;
18-
private final CustomConfig customConfig;
15+
public class CustomShellGenerator extends ASMShellGenerator<CustomConfig> {
1916

2017
public CustomShellGenerator(ShellConfig shellConfig, CustomConfig customConfig) {
21-
this.shellConfig = shellConfig;
22-
this.customConfig = customConfig;
18+
super(shellConfig, customConfig);
2319
}
2420

21+
@Override
2522
public byte[] getBytes() {
26-
String shellClassBase64 = customConfig.getShellClassBase64();
23+
String shellClassBase64 = shellToolConfig.getShellClassBase64();
2724

2825
if (StringUtils.isBlank(shellClassBase64)) {
2926
throw new IllegalArgumentException("Custom shell class is empty");
3027
}
31-
32-
byte[] bytes = ClassRenameUtils.renameClass(Base64.getDecoder().decode(shellClassBase64), customConfig.getShellClassName());
33-
28+
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
29+
byte[] bytes = ClassRenameUtils.renameClass(classBytes, shellToolConfig.getShellClassName());
3430
return ClassBytesShrink.shrink(bytes, shellConfig.isShrink());
3531
}
3632
}
Lines changed: 9 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,31 @@
11
package com.reajason.javaweb.memshell.generator;
22

33
import com.reajason.javaweb.ClassBytesShrink;
4-
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
5-
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
6-
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
74
import com.reajason.javaweb.memshell.config.GodzillaConfig;
85
import com.reajason.javaweb.memshell.config.ShellConfig;
96
import com.reajason.javaweb.memshell.utils.DigestUtils;
10-
import net.bytebuddy.ByteBuddy;
117
import net.bytebuddy.dynamic.DynamicType;
12-
import org.apache.commons.lang3.StringUtils;
138

149
import static net.bytebuddy.matcher.ElementMatchers.named;
1510

1611
/**
1712
* @author ReaJason
1813
* @since 2024/11/23
1914
*/
20-
public class GodzillaGenerator {
21-
private final ShellConfig shellConfig;
22-
private final GodzillaConfig godzillaConfig;
15+
public class GodzillaGenerator extends ByteBuddyShellGenerator<GodzillaConfig> {
2316

2417
public GodzillaGenerator(ShellConfig shellConfig, GodzillaConfig godzillaConfig) {
25-
this.shellConfig = shellConfig;
26-
this.godzillaConfig = godzillaConfig;
18+
super(shellConfig, godzillaConfig);
2719
}
2820

29-
public DynamicType.Builder<?> getBuilder() {
30-
if (godzillaConfig.getShellClass() == null) {
31-
throw new IllegalArgumentException("godzillaConfig.getClazz() == null");
32-
}
33-
if (StringUtils.isBlank(godzillaConfig.getKey()) || StringUtils.isBlank(godzillaConfig.getPass())) {
34-
throw new IllegalArgumentException("godzillaConfig.getKey().isBlank() || godzillaConfig.getPass().isBlank()");
35-
}
36-
String md5Key = DigestUtils.md5Hex(godzillaConfig.getKey()).substring(0, 16);
37-
String md5 = DigestUtils.md5Hex(godzillaConfig.getPass() + md5Key).toUpperCase();
38-
39-
DynamicType.Builder<?> builder = new ByteBuddy()
40-
.redefine(godzillaConfig.getShellClass())
41-
.name(godzillaConfig.getShellClassName())
42-
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
43-
44-
if (shellConfig.isJakarta()) {
45-
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
46-
}
47-
48-
if (shellConfig.isDebugOff()) {
49-
builder = LogRemoveMethodVisitor.extend(builder);
50-
}
51-
52-
return builder.field(named("pass")).value(godzillaConfig.getPass())
21+
@Override
22+
public DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
23+
String md5Key = DigestUtils.md5Hex(shellToolConfig.getKey()).substring(0, 16);
24+
String md5 = DigestUtils.md5Hex(shellToolConfig.getPass() + md5Key).toUpperCase();
25+
return builder.field(named("pass")).value(shellToolConfig.getPass())
5326
.field(named("key")).value(md5Key)
5427
.field(named("md5")).value(md5)
55-
.field(named("headerName")).value(godzillaConfig.getHeaderName())
56-
.field(named("headerValue")).value(godzillaConfig.getHeaderValue());
57-
}
58-
59-
public byte[] getBytes() {
60-
DynamicType.Builder<?> builder = getBuilder();
61-
try (DynamicType.Unloaded<?> make = builder.make()) {
62-
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
63-
}
28+
.field(named("headerName")).value(shellToolConfig.getHeaderName())
29+
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
6430
}
6531
}
Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
package com.reajason.javaweb.memshell.generator;
22

3-
import com.reajason.javaweb.ClassBytesShrink;
4-
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
5-
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
6-
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
73
import com.reajason.javaweb.memshell.config.NeoreGeorgConfig;
84
import com.reajason.javaweb.memshell.config.ShellConfig;
9-
import net.bytebuddy.ByteBuddy;
105
import net.bytebuddy.dynamic.DynamicType;
116

127
import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -15,37 +10,14 @@
1510
* @author ReaJason
1611
* @since 2025/2/12
1712
*/
18-
public class NeoreGeorgGenerator {
19-
private final ShellConfig shellConfig;
20-
private final NeoreGeorgConfig neoreGeorgConfig;
21-
13+
public class NeoreGeorgGenerator extends ByteBuddyShellGenerator<NeoreGeorgConfig> {
2214
public NeoreGeorgGenerator(ShellConfig shellConfig, NeoreGeorgConfig neoreGeorgConfig) {
23-
this.shellConfig = shellConfig;
24-
this.neoreGeorgConfig = neoreGeorgConfig;
25-
}
26-
27-
public DynamicType.Builder<?> getBuilder() {
28-
DynamicType.Builder<?> builder = new ByteBuddy()
29-
.redefine(neoreGeorgConfig.getShellClass())
30-
.name(neoreGeorgConfig.getShellClassName())
31-
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
32-
33-
if (shellConfig.isJakarta()) {
34-
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
35-
}
36-
37-
if (shellConfig.isDebugOff()) {
38-
builder = LogRemoveMethodVisitor.extend(builder);
39-
}
40-
41-
return builder.field(named("headerName")).value(neoreGeorgConfig.getHeaderName())
42-
.field(named("headerValue")).value(neoreGeorgConfig.getHeaderValue());
15+
super(shellConfig, neoreGeorgConfig);
4316
}
4417

45-
public byte[] getBytes() {
46-
DynamicType.Builder<?> builder = getBuilder();
47-
try (DynamicType.Unloaded<?> make = builder.make()) {
48-
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
49-
}
18+
@Override
19+
protected DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
20+
return builder.field(named("headerName")).value(shellToolConfig.getHeaderName())
21+
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
5022
}
5123
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.reajason.javaweb.memshell.generator;
2+
3+
/**
4+
* @author ReaJason
5+
* @since 2025/5/27
6+
*/
7+
public interface ShellGenerator {
8+
9+
byte[] getBytes();
10+
}

0 commit comments

Comments
 (0)