Java .Class file change string

后端 未结 4 1543
耶瑟儿~
耶瑟儿~ 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:34

    There are checksums for the files:

    Archive:  dvt-utils.jar
    Length   Method    Size  Ratio   Date   Time   CRC-32    Name
    --------  ------  ------- -----   ----   ----   ------    ----
    332  Defl:N      226  32%  11.05.31 19:41  a745ad09  META-INF/MANIFEST.MF
    
    0 讨论(0)
  • 2021-01-18 07:36

    I compiled the same class twice with a minor tweak, firstly with "foo" and then with "foo-bar"

    public class HelloWorld {
       public static final String HELLO = "foo-bar";
    }
    

    With "foo"

    000000b0  74 01 00 **03** 66 6f 6f 00  21 00 02 00 03 00 00 00  |t...foo.!.......|
    000000c0  01 00 19 00 04 00 05 00  01 00 06 00 00 00 02 00  |................|
    000000d0  07 00 01 00 01 00 08 00  09 00 01 00 0a 00 00 00  |................|
    000000e0  1d 00 01 00 01 00 00 00  05 2a b7 00 01 b1 00 00  |.........*......|
    000000f0  00 01 00 0b 00 00 00 06  00 01 00 00 00 01 00 01  |................|
    00000100  00 0c 00 00 00 02 00 0d                           |........|
    

    With "foo-bar"

    000000b0  74 01 00 **07** 66 6f 6f 2d  62 61 72 00 21 00 02 00  |t...foo-bar.!...|
    000000c0  03 00 00 00 01 00 19 00  04 00 05 00 01 00 06 00  |................|
    000000d0  00 00 02 00 07 00 01 00  01 00 08 00 09 00 01 00  |................|
    000000e0  0a 00 00 00 1d 00 01 00  01 00 00 00 05 2a b7 00  |.............*..|
    000000f0  01 b1 00 00 00 01 00 0b  00 00 00 06 00 01 00 00  |................|
    00000100  00 01 00 01 00 0c 00 00  00 02 00 0d              |............|
    

    It seems that the length is also encoded in the structure. Note the 3 and the 7... There is more information on this structure

    And with a String of 300 characters the preceding two bytes were 01 2c.

    So given "Gravitation Engine Turned OFF" is 29 characters long, I'd make sure you change the byte immediately before the string to 1D, it should currently be 19 (25 characters for "Gravitation Engine OFF/ON")

    0 讨论(0)
  • 2021-01-18 07:44

    A jar file is a zip file of classes, I guess you've figured that out already. Your best best is to load up a a java IDE with a decompiler addon (pretty sure Intellij has this built in). Once you've decompiled you can change the generated source and recompile it.

    This isn't trivial java stuff, but it's not so complicated either. If you've done some java project development before it's not so hard.

    0 讨论(0)
  • 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[] {  }, "<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"));
      }
    }
    

    (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.

    0 讨论(0)
提交回复
热议问题