如何通过Instruing / ASM实例化不同的类

时间:2016-04-16 17:54:34

标签: java instrumentation java-bytecode-asm bytecode-manipulation

我正在尝试在javaagent to change the class that is being constructedsun/misc/URLClassPath)中使用ASM到从中继承的另一个(fommil/URLClassPath)并覆盖所有方法。我知道目标类(java/net/URLClassLoader),我是retransforming,是唯一创建sun/misc/URLClassPath并且只在其构造函数中创建的东西。

基本理念是这样的:

@Override
public MethodVisitor visitMethod(int access,
                                 String name,
                                 String desc,
                                 String signature,
                                 String[] exceptions) {
    MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);

    return new MethodVisitor(Opcodes.ASM5, visitor) {
        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
            if (opcode == Opcodes.INVOKESPECIAL && "sun/misc/URLClassPath".equals(owner) && "<init>".equals(name)) {
                super.visitMethodInsn(opcode, "fommil/URLClassPath", name, desc, itf);
            } else {
                super.visitMethodInsn(opcode, owner, name, desc, itf);
            }
        }
    };
}

我可以在println的构造函数中添加fommil/URLClassPath,看看它是否正在构建中!

然而,没有调用fommil.URLClassPath个方法。只调用超类上的方法。

即使我更改了上述代码,不仅invokespecial / <init>,而且所有对URLClassPath的调用都会被重写,以便他们的invokevirtual指向我的班级,我的方法仍未调用。我甚至尝试过为URLClassLoader的所有内部类做这个。

那么为什么invokevirtual没有找到覆盖方法,即使它们被重新转换了?我正在做什么 - 改变正在构建的东西的类型 - 从根本上说是不可能的?如果是这样,有人可以解释为什么

我知道修正核心JDK课程是非常邪恶的,但坦率地说,我真的没有其他选择。

唯一要做的就是检测试图实例化URLClassLoader的所有类,并让它们进入内部ucp字段并将其替换为我的实现。

1 个答案:

答案 0 :(得分:0)

我明白了!

考虑这个简单的代码

import java.util.*;    
class Baz {
    public void baz() {
        List list = new ArrayList();
    }
}

产生

   0: new           #2                  // class java/util/ArrayList
   3: dup
   4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
   7: astore_1
   8: return

相比
import java.util.*;    
class Baz {
    public void baz() {
        List list = new LinkedList();
    }
}

产生

   0: new           #2                  // class java/util/LinkedList
   3: dup
   4: invokespecial #3                  // Method java/util/LinkedList."<init>":()V
   7: astore_1
   8: return

请注意其中包含类型的new关键字!

问题是如果想要更改构造函数,还必须更改返回的类型定义。即添加此

        @Override
        public void visitTypeInsn(int opcode, String type) {
            if ("sun/misc/URLClassPath".equals(type))
                super.visitTypeInsn(opcode, "fommil/URLClassPath");
            else
                super.visitTypeInsn(opcode, type);
        }