Java .Class file change string

后端 未结 4 1544
耶瑟儿~
耶瑟儿~ 2021-01-18 07:05

I\'m trying to modify a minecraft mod (gravisuite) that puts \"Gravitation Engine OFF/ON\" whenever I press F, however I want to change this string, I started with replacing

4条回答
  •  囚心锁ツ
    2021-01-18 07:51

    You could have a look at the Apache BCEL (ByteCode Engineering Library). It contains a remarkably powerful class called BCELifier. It is a class that can take an input class, and, when executed, creates a class that, when compiled and executed, creates the input class.

    What?

    Yes. So imagine you have a class containing some strings, like this:

    public class ClassContainingStrings
    {
        private String someString = "Some string";
        public void call()
        {
            System.out.println("Printed string");
            System.out.println(someString);
        }
    }
    

    Now, you can compile this, to obtain the ClassContainingStrings.class file. This file can be fed into the BCELifier, like this:

    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();
        }
    }
    

    It will create a file called ClassContainingStringsCreator.java. For the given example, this will look like this:

    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[] {  }, "", "ClassContainingStrings", il, _cp);
    
        InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0));
        il.append(_factory.createInvoke("java.lang.Object", "", 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"));
      }
    }
    

    (yes, it looks horrible, but that should not matter too much). The important thing is that the strings from the original class, namely the string "Some string" and "Printed string" can be found in there. Now, you can change these strings, and then compile and execute this creator class.

    It will create a new ClassContainingStrings.class, with the modified strings.

提交回复
热议问题