如何在Java上重新定义已定义的类
我希望在下面的代码中调用newTarget.a()和newTarget.b()时应用已调制的ASM类,使其如下所示 在应用修改后的ASM类调用newTarget.a()和newTarget.b()时,如何获得以下结果 代码:如何在Java上重新定义已定义的类,java,java-bytecode-asm,Java,Java Bytecode Asm,我希望在下面的代码中调用newTarget.a()和newTarget.b()时应用已调制的ASM类,使其如下所示 在应用修改后的ASM类调用newTarget.a()和newTarget.b()时,如何获得以下结果 代码: package asm; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import o
package asm;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import static org.objectweb.asm.Opcodes.ASM5;
public class Main {
public static void main(String[] args) throws Exception {
Target target = new Target();
target.a();
target.b();
ClassReader reader = new ClassReader("asm.Main$Target");
ClassWriter writer = new ClassWriter(0);
ClassVisitor visitor = new TestClassVisitor(ASM5, writer);
reader.accept(visitor, 0);
byte[] transformed = writer.toByteArray();
// Apply byte[] transformed
Target newTarget = new Target();
newTarget.a();
newTarget.b();
}
static class Target {
private void a() {
System.out.println("first method");
}
private void b() {
System.out.println("second method");
}
}
static class TestClassVisitor extends ClassVisitor {
public TestClassVisitor(int i, ClassVisitor classVisitor) {
super(i, classVisitor);
}
@Override
public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings) {
MethodVisitor visitor = super.visitMethod(i, s, s1, s2, strings);
if (!s.equals("<init>")) {
return visitor;
}
return new TestMethodVisitor(api, visitor);
}
}
static class TestMethodVisitor extends MethodVisitor {
public TestMethodVisitor(int i, MethodVisitor methodVisitor) {
super(i, methodVisitor);
}
@Override
public void visitCode() {
super.visitCode();
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
super.visitLdcInsn("transformed method");
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
}
@Override
public void visitEnd() {
super.visitEnd();
}
}
}
package-asm;
导入org.objectweb.asm.ClassReader;
导入org.objectweb.asm.ClassVisitor;
导入org.objectweb.asm.ClassWriter;
导入org.objectweb.asm.MethodVisitor;
导入org.objectweb.asm.opcode;
导入静态org.objectweb.asm.Opcodes.ASM5;
公共班机{
公共静态void main(字符串[]args)引发异常{
目标=新目标();
target.a();
target.b();
ClassReader=newclassreader(“asm.Main$Target”);
ClassWriter=新的ClassWriter(0);
ClassVisitor=新的TestClassVisitor(ASM5,编写器);
reader.accept(访问者,0);
byte[]transformed=writer.toByteArray();
//应用已转换的字节[]
Target newTarget=新目标();
新目标a();
newTarget.b();
}
静态类目标{
私人文件a(){
System.out.println(“第一种方法”);
}
私人空间b(){
System.out.println(“第二种方法”);
}
}
静态类TestClassVisitor扩展了ClassVisitor{
公共TestClassVisitor(inti,ClassVisitor){
超级(i类访客);
}
@凌驾
public方法访问者访问方法(int i、字符串s、字符串s1、字符串s2、字符串[]字符串){
MethodVisitor=super.visitMethod(i、s、s1、s2、字符串);
如果(!s.equals(“”){
回访者;
}
返回新的TestMethodVisitor(api,visitor);
}
}
静态类TestMethodVisitor扩展了MethodVisitor{
公共TestMethodVisitor(int i,MethodVisitor MethodVisitor){
超级(i,访客);
}
@凌驾
公共无效访问代码(){
super.visitCode();
super.visitFieldInsn(Opcodes.GETSTATIC,“java/lang/System”,“out”,“Ljava/io/PrintStream;”);
super.visitldcinn(“转换方法”);
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,“java/io/PrintStream”,“println”,“Ljava/lang/String;)V”,false);
}
@凌驾
公共图书馆{
super.visitEnd();
}
}
}
想要结果:
package asm;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import static org.objectweb.asm.Opcodes.ASM5;
public class Main {
public static void main(String[] args) throws Exception {
Target target = new Target();
target.a();
target.b();
ClassReader reader = new ClassReader("asm.Main$Target");
ClassWriter writer = new ClassWriter(0);
ClassVisitor visitor = new TestClassVisitor(ASM5, writer);
reader.accept(visitor, 0);
byte[] transformed = writer.toByteArray();
// Apply byte[] transformed
Target newTarget = new Target();
newTarget.a();
newTarget.b();
}
static class Target {
private void a() {
System.out.println("first method");
}
private void b() {
System.out.println("second method");
}
}
static class TestClassVisitor extends ClassVisitor {
public TestClassVisitor(int i, ClassVisitor classVisitor) {
super(i, classVisitor);
}
@Override
public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings) {
MethodVisitor visitor = super.visitMethod(i, s, s1, s2, strings);
if (!s.equals("<init>")) {
return visitor;
}
return new TestMethodVisitor(api, visitor);
}
}
static class TestMethodVisitor extends MethodVisitor {
public TestMethodVisitor(int i, MethodVisitor methodVisitor) {
super(i, methodVisitor);
}
@Override
public void visitCode() {
super.visitCode();
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
super.visitLdcInsn("transformed method");
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
}
@Override
public void visitEnd() {
super.visitEnd();
}
}
}
第一种方法
第二种方法
变换方法
第一种方法
变换方法
第二种方法是您正在寻找的。它要求您通过-javaagent
参数连接Java代理。使用API,您可以调用:
instrumentation.redefineClasses(
new ClassDefinition(asm.Main.Target.class, classWriter.toBytes())
);
请确保不要更改类的布局,因为大多数JVM目前都不支持此操作。您正在查找。它要求您通过-javaagent
参数连接Java代理。使用API,您可以调用:
instrumentation.redefineClasses(
new ClassDefinition(asm.Main.Target.class, classWriter.toBytes())
);
请确保不要更改类的布局,大多数JVM目前都不支持此功能。您尝试了什么,得到了什么,您是如何尝试的?@FlyingZombie我想分析特定的类。为此,我需要重新定义类。但是我不知道怎么做。你尝试了什么,得到了什么,你是怎么尝试的?@FlyingZombie我想分析一下特定的类。为此,我需要重新定义类。但是我不知道怎么做。我尝试了这个,但是收到了
java.lang.IllegalAccessError:试图访问类~~~
和java.lang.CompatibleClassChangeError
。仅打开一个空代理将导致错误。你知道这个错误吗?如果你得到一个不兼容的类更改错误,你添加了一个字段、一个方法或修改了一个大多数JVM都不支持的修改器。我尝试了这个,但收到了java.lang.IllegalAccessError:试图访问类~~~
和java.lang.CompatibleClassChangeError
。仅打开一个空代理将导致错误。您知道这个错误吗?如果您得到一个不兼容的类更改错误,那么您添加了一个字段、一个方法或更改了一个大多数JVM不支持的修饰符。