Skip to content

Commit 9d82a71

Browse files
committed
feat: support staticInitialize
1 parent 587c345 commit 9d82a71

File tree

19 files changed

+109
-24
lines changed

19 files changed

+109
-24
lines changed

generator/src/main/java/com/reajason/javaweb/memshell/config/InjectorConfig.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,9 @@ public class InjectorConfig {
4646
* 内存马类字节
4747
*/
4848
private byte[] shellClassBytes;
49+
50+
/**
51+
* 添加静态代码块调用构造方法初始化
52+
*/
53+
private boolean staticInitialize;
4954
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.reajason.javaweb.ClassBytesShrink;
44
import com.reajason.javaweb.asm.InnerClassDiscovery;
55
import com.reajason.javaweb.buddy.*;
6+
import com.reajason.javaweb.memshell.ShellType;
67
import com.reajason.javaweb.memshell.config.InjectorConfig;
78
import com.reajason.javaweb.memshell.config.ShellConfig;
89
import com.reajason.javaweb.utils.CommonUtil;
@@ -59,6 +60,10 @@ public DynamicType.Builder<?> getBuilder() {
5960
if (shellConfig.isDebugOff()) {
6061
builder = LogRemoveMethodVisitor.extend(builder);
6162
}
63+
64+
if (injectorConfig.isStaticInitialize() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
65+
builder = StaticBlockSelfConstructorCall.extend(builder);
66+
}
6267
return builder;
6368
}
6469

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,20 @@ public class ValveGenerator {
3232

3333
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) {
3434
String packageName = null;
35-
if (serverVersion.equals("6")) {
36-
packageName = TONGWEB6_VALVE_PACKAGE;
37-
} else if (serverVersion.equals("7")) {
38-
packageName = TONGWEB7_VALVE_PACKAGE;
39-
} else if (serverVersion.equals("8")) {
40-
packageName = TONGWEB8_VALVE_PACKAGE;
41-
} else if (shell instanceof Bes) {
35+
if (serverVersion != null) {
36+
switch (serverVersion) {
37+
case "6":
38+
packageName = TONGWEB6_VALVE_PACKAGE;
39+
break;
40+
case "7":
41+
packageName = TONGWEB7_VALVE_PACKAGE;
42+
break;
43+
case "8":
44+
packageName = TONGWEB8_VALVE_PACKAGE;
45+
break;
46+
}
47+
}
48+
if (shell instanceof Bes) {
4249
packageName = BES_VALVE_PACKAGE;
4350
}
4451
if (StringUtils.isEmpty(packageName)) {

generator/src/main/java/com/reajason/javaweb/probe/config/ProbeConfig.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ public class ProbeConfig {
4747
@Builder.Default
4848
private boolean shrink = false;
4949

50+
/**
51+
* 是否添加静态代码块调用构造方法
52+
*/
53+
@Builder.Default
54+
private boolean staticInitialize = false;
55+
5056
public boolean isDebugOff() {
5157
return !debug;
5258
}

generator/src/main/java/com/reajason/javaweb/probe/generator/ByteBuddyShellGenerator.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.reajason.javaweb.ShellGenerator;
55
import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor;
66
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
7+
import com.reajason.javaweb.buddy.StaticBlockSelfConstructorCall;
78
import com.reajason.javaweb.probe.config.ProbeConfig;
89
import com.reajason.javaweb.probe.config.ProbeContentConfig;
910
import net.bytebuddy.ByteBuddy;
@@ -27,13 +28,19 @@ public ByteBuddyShellGenerator(ProbeConfig probeConfig, T probeContentConfig) {
2728
@Override
2829
public byte[] getBytes() {
2930
DynamicType.Builder<?> builder = build(new ByteBuddy());
31+
3032
if (probeConfig.needByPassJavaModule()) {
3133
builder = ByPassJavaModuleInterceptor.extend(builder);
3234
}
35+
3336
if (probeConfig.isDebugOff()) {
3437
builder = LogRemoveMethodVisitor.extend(builder);
3538
}
3639

40+
if (probeConfig.isStaticInitialize()) {
41+
builder = StaticBlockSelfConstructorCall.extend(builder);
42+
}
43+
3744
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
3845
return ClassBytesShrink.shrink(unloaded.getBytes(), probeConfig.isShrink());
3946
}

integration-test/src/test/java/com/reajason/javaweb/integration/ProbeAssertion.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public static void responseBytecodeIsOk(String url, String server, int targetJre
2929
.targetJreVersion(targetJreVersion)
3030
.debug(true)
3131
.shrink(true)
32+
.staticInitialize(true)
3233
.build();
3334
String reqParamName = "payload";
3435
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
@@ -57,6 +58,7 @@ public static void responseBytecodeWithoutPrefixIsOk(String url, String server,
5758
.targetJreVersion(targetJreVersion)
5859
.debug(true)
5960
.shrink(true)
61+
.staticInitialize(true)
6062
.build();
6163
String reqParamName = "payload";
6264
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
@@ -84,6 +86,7 @@ public static void responseCommandIsOk(String url, String server, int targetJreV
8486
.probeContent(ProbeContent.Command)
8587
.debug(true)
8688
.shrink(true)
89+
.staticInitialize(true)
8790
.targetJreVersion(targetJreVersion)
8891
.build();
8992
String headerName = "X-Header";

integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,20 @@ public static Pair<String, String> getUrls(String url, String shellType, String
8484

8585
@SneakyThrows
8686
public static void shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer, GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
87+
shellInjectIsOk(url, server, null, shellType, shellTool, targetJdkVersion, packer, appContainer, pythonContainer);
88+
}
89+
90+
@SneakyThrows
91+
public static void shellInjectIsOk(String url, String server, String serverVersion, String shellType, String shellTool,
92+
int targetJdkVersion, Packers packer,
93+
GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
8794
Pair<String, String> urls = getUrls(url, shellType, shellTool, packer);
8895
String shellUrl = urls.getLeft();
8996
String urlPattern = urls.getRight();
9097

9198
ShellToolConfig shellToolConfig = getShellToolConfig(shellType, shellTool, packer);
9299

93-
MemShellResult generateResult = generate(urlPattern, server, shellType, shellTool, targetJdkVersion, shellToolConfig, packer);
100+
MemShellResult generateResult = generate(urlPattern, server, serverVersion, shellType, shellTool, targetJdkVersion, shellToolConfig, packer);
94101

95102
packerResultAndInject(generateResult, url, shellTool, shellType, packer, appContainer);
96103

@@ -107,7 +114,7 @@ public static void packerResultAndInject(MemShellResult generateResult, String u
107114
String jarPath = "/" + shellTool + shellType + packer.name() + ".jar";
108115
appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath);
109116
FileUtils.deleteQuietly(tempJar.toFile());
110-
String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout();
117+
String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout().trim();
111118
assertDoesNotThrow(() -> Long.parseLong(pidInContainer));
112119
String stdout = appContainer.execInContainer("/jattach", pidInContainer, "load", "instrument", "false", jarPath).getStdout();
113120
log.info("attach result: {}", stdout);
@@ -291,8 +298,8 @@ public static ShellToolConfig getShellToolConfig(String shellType, String shellT
291298
return shellToolConfig;
292299
}
293300

294-
public static MemShellResult generate(String urlPattern, String server, String shellType, String shellTool, int targetJdkVersion, ShellToolConfig shellToolConfig, Packers packer) {
295-
InjectorConfig injectorConfig = new InjectorConfig();
301+
public static MemShellResult generate(String urlPattern, String server, String serverVersin, String shellType, String shellTool, int targetJdkVersion, ShellToolConfig shellToolConfig, Packers packer) {
302+
InjectorConfig injectorConfig = InjectorConfig.builder().staticInitialize(true).build();
296303
if (StringUtils.isNotBlank(urlPattern)) {
297304
injectorConfig.setUrlPattern(urlPattern);
298305
}
@@ -304,6 +311,7 @@ public static MemShellResult generate(String urlPattern, String server, String s
304311

305312
ShellConfig shellConfig = ShellConfig.builder()
306313
.server(server)
314+
.serverVersion(serverVersin)
307315
.shellTool(shellTool)
308316
.shellType(shellType)
309317
.targetJreVersion(targetJdkVersion)

web/bun.lockb

2.77 KB
Binary file not shown.

web/package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,27 @@
1515
},
1616
"devDependencies": {
1717
"@biomejs/biome": "2.1.4",
18-
"@react-router/dev": "^7.9.5",
19-
"@types/node": "^24.10.0",
20-
"@types/react": "^19.2.2",
18+
"@react-router/dev": "^7.9.6",
19+
"@types/node": "^24.10.1",
20+
"@types/react": "^19.2.5",
2121
"@types/react-copy-to-clipboard": "^5.0.7",
22-
"@types/react-dom": "^19.2.2",
22+
"@types/react-dom": "^19.2.3",
2323
"@types/react-syntax-highlighter": "^15.5.13",
24-
"@vitejs/plugin-react": "^5.1.0",
24+
"@vitejs/plugin-react": "^5.1.1",
2525
"rimraf": "^6.1.0",
26-
"tailwindcss": "^4.1.16",
26+
"tailwindcss": "^4.1.17",
2727
"typescript": "^5.9.3",
28-
"vite": "^7.1.12",
28+
"vite": "^7.2.2",
2929
"vite-bundle-visualizer": "^1.2.1"
3030
},
3131
"dependencies": {
3232
"@hookform/resolvers": "^5.2.2",
33-
"@tailwindcss/vite": "^4.1.16",
34-
"@tanstack/react-query": "^5.90.6",
33+
"@tailwindcss/vite": "^4.1.17",
34+
"@tanstack/react-query": "^5.90.9",
3535
"class-variance-authority": "^0.7.1",
3636
"clsx": "^2.1.1",
3737
"framer-motion": "^12.23.24",
38-
"i18next": "^25.6.0",
38+
"i18next": "^25.6.2",
3939
"lucide-react": "^0.539.0",
4040
"motion": "^12.23.24",
4141
"radix-ui": "^1.4.3",
@@ -44,11 +44,11 @@
4444
"react-dom": "^19.2.0",
4545
"react-hook-form": "^7.66.0",
4646
"react-i18next": "^15.7.4",
47-
"react-router": "^7.9.5",
48-
"react-router-dom": "^7.9.5",
47+
"react-router": "^7.9.6",
48+
"react-router-dom": "^7.9.6",
4949
"react-syntax-highlighter": "^15.6.6",
5050
"sonner": "^2.0.7",
51-
"tailwind-merge": "^3.3.1",
51+
"tailwind-merge": "^3.4.0",
5252
"tw-animate-css": "^1.4.0",
5353
"yup": "^1.7.1"
5454
},

web/src/components/memshell/main-config-card.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,22 @@ export default function MainConfigCard({
383383
</FormItem>
384384
)}
385385
/>
386+
<FormField
387+
control={form.control}
388+
name="staticInitialize"
389+
render={({ field }) => (
390+
<FormItem className="flex items-center space-x-2 space-y-0">
391+
<FormControl>
392+
<Switch
393+
id="staticInitialize"
394+
checked={field.value}
395+
onCheckedChange={field.onChange}
396+
/>
397+
</FormControl>
398+
<Label htmlFor="staticInitialize">{t("common:staticInitialize")}</Label>
399+
</FormItem>
400+
)}
401+
/>
386402
</div>
387403
</CardContent>
388404
</Card>

0 commit comments

Comments
 (0)