mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: support staticInitialize
This commit is contained in:
@@ -46,4 +46,9 @@ public class InjectorConfig {
|
||||
* 内存马类字节
|
||||
*/
|
||||
private byte[] shellClassBytes;
|
||||
|
||||
/**
|
||||
* 添加静态代码块调用构造方法初始化
|
||||
*/
|
||||
private boolean staticInitialize;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.reajason.javaweb.memshell.generator;
|
||||
import com.reajason.javaweb.ClassBytesShrink;
|
||||
import com.reajason.javaweb.asm.InnerClassDiscovery;
|
||||
import com.reajason.javaweb.buddy.*;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.utils.CommonUtil;
|
||||
@@ -59,6 +60,10 @@ public class InjectorGenerator {
|
||||
if (shellConfig.isDebugOff()) {
|
||||
builder = LogRemoveMethodVisitor.extend(builder);
|
||||
}
|
||||
|
||||
if (injectorConfig.isStaticInitialize() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
||||
builder = StaticBlockSelfConstructorCall.extend(builder);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
+14
-7
@@ -32,13 +32,20 @@ public class ValveGenerator {
|
||||
|
||||
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) {
|
||||
String packageName = null;
|
||||
if (serverVersion.equals("6")) {
|
||||
packageName = TONGWEB6_VALVE_PACKAGE;
|
||||
} else if (serverVersion.equals("7")) {
|
||||
packageName = TONGWEB7_VALVE_PACKAGE;
|
||||
} else if (serverVersion.equals("8")) {
|
||||
packageName = TONGWEB8_VALVE_PACKAGE;
|
||||
} else if (shell instanceof Bes) {
|
||||
if (serverVersion != null) {
|
||||
switch (serverVersion) {
|
||||
case "6":
|
||||
packageName = TONGWEB6_VALVE_PACKAGE;
|
||||
break;
|
||||
case "7":
|
||||
packageName = TONGWEB7_VALVE_PACKAGE;
|
||||
break;
|
||||
case "8":
|
||||
packageName = TONGWEB8_VALVE_PACKAGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shell instanceof Bes) {
|
||||
packageName = BES_VALVE_PACKAGE;
|
||||
}
|
||||
if (StringUtils.isEmpty(packageName)) {
|
||||
|
||||
@@ -47,6 +47,12 @@ public class ProbeConfig {
|
||||
@Builder.Default
|
||||
private boolean shrink = false;
|
||||
|
||||
/**
|
||||
* 是否添加静态代码块调用构造方法
|
||||
*/
|
||||
@Builder.Default
|
||||
private boolean staticInitialize = false;
|
||||
|
||||
public boolean isDebugOff() {
|
||||
return !debug;
|
||||
}
|
||||
|
||||
+7
@@ -4,6 +4,7 @@ import com.reajason.javaweb.ClassBytesShrink;
|
||||
import com.reajason.javaweb.ShellGenerator;
|
||||
import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor;
|
||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||
import com.reajason.javaweb.buddy.StaticBlockSelfConstructorCall;
|
||||
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||
import com.reajason.javaweb.probe.config.ProbeContentConfig;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
@@ -27,13 +28,19 @@ public abstract class ByteBuddyShellGenerator<T extends ProbeContentConfig> impl
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
DynamicType.Builder<?> builder = build(new ByteBuddy());
|
||||
|
||||
if (probeConfig.needByPassJavaModule()) {
|
||||
builder = ByPassJavaModuleInterceptor.extend(builder);
|
||||
}
|
||||
|
||||
if (probeConfig.isDebugOff()) {
|
||||
builder = LogRemoveMethodVisitor.extend(builder);
|
||||
}
|
||||
|
||||
if (probeConfig.isStaticInitialize()) {
|
||||
builder = StaticBlockSelfConstructorCall.extend(builder);
|
||||
}
|
||||
|
||||
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
|
||||
return ClassBytesShrink.shrink(unloaded.getBytes(), probeConfig.isShrink());
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public class ProbeAssertion {
|
||||
.targetJreVersion(targetJreVersion)
|
||||
.debug(true)
|
||||
.shrink(true)
|
||||
.staticInitialize(true)
|
||||
.build();
|
||||
String reqParamName = "payload";
|
||||
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
|
||||
@@ -57,6 +58,7 @@ public class ProbeAssertion {
|
||||
.targetJreVersion(targetJreVersion)
|
||||
.debug(true)
|
||||
.shrink(true)
|
||||
.staticInitialize(true)
|
||||
.build();
|
||||
String reqParamName = "payload";
|
||||
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
|
||||
@@ -84,6 +86,7 @@ public class ProbeAssertion {
|
||||
.probeContent(ProbeContent.Command)
|
||||
.debug(true)
|
||||
.shrink(true)
|
||||
.staticInitialize(true)
|
||||
.targetJreVersion(targetJreVersion)
|
||||
.build();
|
||||
String headerName = "X-Header";
|
||||
|
||||
+12
-4
@@ -84,13 +84,20 @@ public class ShellAssertion {
|
||||
|
||||
@SneakyThrows
|
||||
public static void shellInjectIsOk(String url, String server, String shellType, String shellTool, int targetJdkVersion, Packers packer, GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
|
||||
shellInjectIsOk(url, server, null, shellType, shellTool, targetJdkVersion, packer, appContainer, pythonContainer);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static void shellInjectIsOk(String url, String server, String serverVersion, String shellType, String shellTool,
|
||||
int targetJdkVersion, Packers packer,
|
||||
GenericContainer<?> appContainer, GenericContainer<?> pythonContainer) {
|
||||
Pair<String, String> urls = getUrls(url, shellType, shellTool, packer);
|
||||
String shellUrl = urls.getLeft();
|
||||
String urlPattern = urls.getRight();
|
||||
|
||||
ShellToolConfig shellToolConfig = getShellToolConfig(shellType, shellTool, packer);
|
||||
|
||||
MemShellResult generateResult = generate(urlPattern, server, shellType, shellTool, targetJdkVersion, shellToolConfig, packer);
|
||||
MemShellResult generateResult = generate(urlPattern, server, serverVersion, shellType, shellTool, targetJdkVersion, shellToolConfig, packer);
|
||||
|
||||
packerResultAndInject(generateResult, url, shellTool, shellType, packer, appContainer);
|
||||
|
||||
@@ -107,7 +114,7 @@ public class ShellAssertion {
|
||||
String jarPath = "/" + shellTool + shellType + packer.name() + ".jar";
|
||||
appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath);
|
||||
FileUtils.deleteQuietly(tempJar.toFile());
|
||||
String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout();
|
||||
String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout().trim();
|
||||
assertDoesNotThrow(() -> Long.parseLong(pidInContainer));
|
||||
String stdout = appContainer.execInContainer("/jattach", pidInContainer, "load", "instrument", "false", jarPath).getStdout();
|
||||
log.info("attach result: {}", stdout);
|
||||
@@ -291,8 +298,8 @@ public class ShellAssertion {
|
||||
return shellToolConfig;
|
||||
}
|
||||
|
||||
public static MemShellResult generate(String urlPattern, String server, String shellType, String shellTool, int targetJdkVersion, ShellToolConfig shellToolConfig, Packers packer) {
|
||||
InjectorConfig injectorConfig = new InjectorConfig();
|
||||
public static MemShellResult generate(String urlPattern, String server, String serverVersin, String shellType, String shellTool, int targetJdkVersion, ShellToolConfig shellToolConfig, Packers packer) {
|
||||
InjectorConfig injectorConfig = InjectorConfig.builder().staticInitialize(true).build();
|
||||
if (StringUtils.isNotBlank(urlPattern)) {
|
||||
injectorConfig.setUrlPattern(urlPattern);
|
||||
}
|
||||
@@ -304,6 +311,7 @@ public class ShellAssertion {
|
||||
|
||||
ShellConfig shellConfig = ShellConfig.builder()
|
||||
.server(server)
|
||||
.serverVersion(serverVersin)
|
||||
.shellTool(shellTool)
|
||||
.shellType(shellType)
|
||||
.targetJreVersion(targetJdkVersion)
|
||||
|
||||
Binary file not shown.
+13
-13
@@ -15,27 +15,27 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.1.4",
|
||||
"@react-router/dev": "^7.9.5",
|
||||
"@types/node": "^24.10.0",
|
||||
"@types/react": "^19.2.2",
|
||||
"@react-router/dev": "^7.9.6",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/react": "^19.2.5",
|
||||
"@types/react-copy-to-clipboard": "^5.0.7",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@vitejs/plugin-react": "^5.1.0",
|
||||
"@vitejs/plugin-react": "^5.1.1",
|
||||
"rimraf": "^6.1.0",
|
||||
"tailwindcss": "^4.1.16",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.1.12",
|
||||
"vite": "^7.2.2",
|
||||
"vite-bundle-visualizer": "^1.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@tailwindcss/vite": "^4.1.16",
|
||||
"@tanstack/react-query": "^5.90.6",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@tanstack/react-query": "^5.90.9",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^12.23.24",
|
||||
"i18next": "^25.6.0",
|
||||
"i18next": "^25.6.2",
|
||||
"lucide-react": "^0.539.0",
|
||||
"motion": "^12.23.24",
|
||||
"radix-ui": "^1.4.3",
|
||||
@@ -44,11 +44,11 @@
|
||||
"react-dom": "^19.2.0",
|
||||
"react-hook-form": "^7.66.0",
|
||||
"react-i18next": "^15.7.4",
|
||||
"react-router": "^7.9.5",
|
||||
"react-router-dom": "^7.9.5",
|
||||
"react-router": "^7.9.6",
|
||||
"react-router-dom": "^7.9.6",
|
||||
"react-syntax-highlighter": "^15.6.6",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"yup": "^1.7.1"
|
||||
},
|
||||
|
||||
@@ -383,6 +383,22 @@ export default function MainConfigCard({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="staticInitialize"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="staticInitialize"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<Label htmlFor="staticInitialize">{t("common:staticInitialize")}</Label>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -324,6 +324,24 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="staticInitialize"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="staticInitialize"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<Label htmlFor="staticInitialize">
|
||||
{t("common:staticInitialize")}
|
||||
</Label>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
[form.control, t],
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"server": "Server",
|
||||
"serverVersion": "Server Version",
|
||||
"shrink": "Shrink",
|
||||
"staticInitialize": "StaticInitialize",
|
||||
"toast.generateError": "Generation failed, {{error}}",
|
||||
"toast.generateSuccess": "Generation successful",
|
||||
"urlPattern": "URL Pattern",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"server": "服务类型",
|
||||
"serverVersion": "服务版本",
|
||||
"shrink": "缩小字节码",
|
||||
"staticInitialize": "静态初始化",
|
||||
"toast.generateError": "生成失败,{{error}}",
|
||||
"toast.generateSuccess": "生成成功",
|
||||
"urlPattern": "请求路径",
|
||||
|
||||
@@ -77,6 +77,7 @@ export default function MemShellPage() {
|
||||
injectorClassName: urlParams.injectorClassName ?? "",
|
||||
packingMethod: urlParams.packingMethod ?? "",
|
||||
shrink: urlParams.shrink ?? true,
|
||||
staticInitialize: true,
|
||||
shellClassBase64: urlParams.shellClassBase64 ?? "",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -57,6 +57,7 @@ export default function ProbeShellGenerator() {
|
||||
seconds: 5,
|
||||
sleepServer: "Tomcat",
|
||||
shrink: true,
|
||||
staticInitialize: true
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ export interface InjectorConfig {
|
||||
injectorClassName?: string;
|
||||
classInheritance?: string;
|
||||
urlPattern?: string;
|
||||
staticInitialize?: boolean;
|
||||
}
|
||||
|
||||
export interface ConfigResponseType {
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface ProbeConfig {
|
||||
debug?: boolean;
|
||||
byPassJavaModule?: boolean;
|
||||
shrink?: boolean;
|
||||
staticInitialize?: boolean;
|
||||
}
|
||||
|
||||
export interface ProbeContentConfig {
|
||||
|
||||
@@ -10,6 +10,7 @@ export const memShellFormSchema = yup.object({
|
||||
targetJdkVersion: yup.string().optional(),
|
||||
debug: yup.boolean().optional(),
|
||||
byPassJavaModule: yup.boolean().optional(),
|
||||
staticInitialize: yup.boolean().optional(),
|
||||
shellClassName: yup.string().optional(),
|
||||
shellTool: yup.string().required().min(1),
|
||||
shellType: yup.string().required().min(1),
|
||||
@@ -152,6 +153,7 @@ export const probeShellFormSchema = yup.object().shape({
|
||||
debug: yup.boolean().optional(),
|
||||
byPassJavaModule: yup.boolean().optional(),
|
||||
shrink: yup.boolean().optional(),
|
||||
staticInitialize: yup.boolean().optional()
|
||||
});
|
||||
|
||||
type ProbeValidationResult = ResolverResult<ProbeShellFormSchema>;
|
||||
|
||||
@@ -37,6 +37,7 @@ export function transformToPostData(formValue: MemShellFormSchema) {
|
||||
const injectorConfig: InjectorConfig = {
|
||||
urlPattern: formValue.urlPattern,
|
||||
injectorClassName: formValue.injectorClassName,
|
||||
staticInitialize: formValue.staticInitialize
|
||||
};
|
||||
return {
|
||||
shellConfig,
|
||||
@@ -54,6 +55,7 @@ export function transformToProbePostData(formValue: ProbeShellFormSchema) {
|
||||
shrink: formValue.shrink,
|
||||
debug: formValue.debug,
|
||||
byPassJavaModule: formValue.byPassJavaModule,
|
||||
staticInitialize: formValue.staticInitialize
|
||||
};
|
||||
const probeContentConfig: ProbeContentConfig = {
|
||||
host: formValue.host,
|
||||
|
||||
Reference in New Issue
Block a user