您可以查看
Apache BCEL(字节码工程库),它包含一个非常强大的类,名为
BCELifier
。这是一个类,可以接受一个输入类,并在执行时创建一个类,该类编译并执行后将创建输入类。
什么?
是的。所以想象一下您有一个包含一些字符串的类,像这样:
public class ClassContainingStrings
{
private String someString = "Some string";
public void call()
{
System.out.println("Printed string");
System.out.println(someString);
}
}
现在,您可以编译此代码,以获取ClassContainingStrings.class
文件。该文件可被输入到BCELifier
中,如下所示:
import java.io.FileOutputStream;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.util.BCELifier;
public class ChangeStringInClassFile
{
public static void main(String[] args) throws Exception
{
String classFileName = "ClassContainingStrings.class";
JavaClass c = new ClassParser(classFileName).parse();
BCELifier b = new BCELifier(c,
new FileOutputStream("ClassContainingStringsCreator.java"));
b.start();
}
}
它将创建一个名为
ClassContainingStringsCreator.java
的文件。对于给定的示例,它将如下所示:
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.*;
import org.apache.bcel.*;
import java.io.*;
public class ClassContainingStringsCreator implements Constants {
private InstructionFactory _factory;
private ConstantPoolGen _cp;
private ClassGen _cg;
public ClassContainingStringsCreator() {
_cg = new ClassGen("ClassContainingStrings", "java.lang.Object", "ClassContainingStrings.java", ACC_PUBLIC | ACC_SUPER, new String[] { });
_cp = _cg.getConstantPool();
_factory = new InstructionFactory(_cg, _cp);
}
public void create(OutputStream out) throws IOException {
createFields();
createMethod_0();
createMethod_1();
_cg.getJavaClass().dump(out);
}
private void createFields() {
FieldGen field;
field = new FieldGen(ACC_PRIVATE, Type.STRING, "someString", _cp);
_cg.addField(field.getField());
}
private void createMethod_0() {
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] { }, "<init>", "ClassContainingStrings", il, _cp);
InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0));
il.append(_factory.createInvoke("java.lang.Object", "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
InstructionHandle ih_4 = il.append(_factory.createLoad(Type.OBJECT, 0));
il.append(new PUSH(_cp, "Some string"));
il.append(_factory.createFieldAccess("ClassContainingStrings", "someString", Type.STRING, Constants.PUTFIELD));
InstructionHandle ih_10 = il.append(_factory.createReturn(Type.VOID));
method.setMaxStack();
method.setMaxLocals();
_cg.addMethod(method.getMethod());
il.dispose();
}
private void createMethod_1() {
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] { }, "call", "ClassContainingStrings", il, _cp);
InstructionHandle ih_0 = il.append(_factory.createFieldAccess("java.lang.System", "out", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
il.append(new PUSH(_cp, "Printed string"));
il.append(_factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));
InstructionHandle ih_8 = il.append(_factory.createFieldAccess("java.lang.System", "out", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
il.append(_factory.createLoad(Type.OBJECT, 0));
il.append(_factory.createFieldAccess("ClassContainingStrings", "someString", Type.STRING, Constants.GETFIELD));
il.append(_factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));
InstructionHandle ih_18 = il.append(_factory.createReturn(Type.VOID));
method.setMaxStack();
method.setMaxLocals();
_cg.addMethod(method.getMethod());
il.dispose();
}
public static void main(String[] args) throws Exception {
ClassContainingStringsCreator creator = new ClassContainingStringsCreator();
creator.create(new FileOutputStream("ClassContainingStrings.class"));
}
}
(是的,它看起来很丑,但那并不太重要)。重要的是,可以在原始类中找到字符串“Some string”和“Printed string”。您现在可以更改这些字符串,然后编译并执行此创建者类。
它将创建一个新的ClassContainingStrings.class,并带有修改后的字符串。