BCel 即时修补方法不起作用

BCel patching a method on the fly not working

我正在尝试使用 BCEL 将回调插入到 Java 方法中,但从未调用该回调。程序运行时就好像根本没有检测过一样。

我所做的精简版:

package com.github.worldsender;

import java.lang.reflect.InvocationTargetException;

import org.apache.bcel.*;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;

public class CustomHook {
    public static void callback() {
        System.out.println("Success");
    }

    private static JavaClass getOriginal() {
        try {
            return Repository.lookupClass("com.github.worldsender.Foo");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Foo not found.", e);
        }
    }

    private static ClassGen modClass(ClassGen classGen) {
        for (Method method : classGen.getMethods()) {
            if (!method.getName().equals("main"))
                continue;
            classGen.removeMethod(method);
            MethodGen methodGen = modConstructor(classGen, method);
            classGen.addMethod(methodGen.getMethod());
            methodGen.getInstructionList().dispose();
            return classGen;
        }
        throw new RuntimeException("Method not found, abort");
    }

    private static MethodGen modConstructor(ClassGen classGen, Method constructor) {
        InstructionFactory factory = new InstructionFactory(classGen);
        ConstantPoolGen constants = classGen.getConstantPool();
        MethodGen methodGen = new MethodGen(constructor, classGen.getClassName(), constants);

        InstructionList ilist = methodGen.getInstructionList();

        String invokedClass = "com.github.worldsender.CustomHook";
        String invokedMethod = "callback";
        Type returnType = Type.VOID;
        Type[] arguments = Type.NO_ARGS;
        short invokeType = Constants.INVOKESTATIC;
        InvokeInstruction invoke = factory.createInvoke(invokedClass, invokedMethod, returnType, arguments, invokeType);

        ilist.insert(invoke);
        methodGen.stripAttributes(true);
        methodGen.setMaxStack();
        methodGen.setMaxLocals();
        return methodGen;
    }

    public static void main(String[] args) throws Exception {
        JavaClass original = getOriginal();
        ClassGen modClass = new ClassGen(original);
        modClass = modClass(modClass);

        Repository.removeClass(original);
        Repository.addClass(modClass.getJavaClass());

        Class<?> minecraftMain = Class.forName("com.github.worldsender.Foo");

        java.lang.reflect.Method meth = minecraftMain.getMethod("main", String[].class);
        meth.invoke(null, (Object) args);
    }
}
//// Other class
package com.github.worldsender;

public class Foo {
    public static void main(String[] args) {
        System.out.println("Here");
    }
}

打印的全部是:

Here

我期待的是:

Success
Here

我做错了什么?

调用时

Repository.addClass(modClass.getJavaClass())

您正在将 class 添加到 BCEL 存储库,而不是当前 VM 的 class 路径。调用时

Class.forName("com.github.worldsender.Foo")

然而,您是在指示虚拟机从 class 路径加载未修改的 class 文件。因此,您无法观察到任何效果。查看 BCEL 的 built-in class loader 以加载生成的 class.