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.
我正在尝试使用 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.