有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JAVA类文件更改字符串

我试图修改一个minecraft mod(gravisuite),每当我按下F键时,它就会“关闭/打开重力引擎”,但是我想改变这个字符串,我开始使用十六进制编辑器将“重力引擎关闭”替换为“重力引擎关闭”,但之后该文件不再有效:/我尝试使用jbe、cjbe和rej等工具,该字符串位于常量池中,但它只允许我删除它

有没有办法在编译的java类中更改字符串而不破坏它

谢谢


共 (4) 个答案

  1. # 1 楼答案

    这些文件有校验和:

    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
    
  2. # 2 楼答案

    我对同一个类进行了两次编译,首先是“foo”,然后是“foobar”

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

    用“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                           |........|
    

    用“富吧”

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

    似乎长度也被编码在结构中。注意3和7。。。有more information on this structure

    对于300个字符的字符串,前两个字节是01 2c

    如果“重力引擎关闭”是29个字符长,我会确保您将字符串前面的字节更改为1D,它当前应该是19个字符(25个字符表示“重力引擎关闭/打开”)

  3. # 3 楼答案

    你可以看看Apache BCEL (ByteCode Engineering Library)。它包含一个非常强大的类^{}。它是一个可以接受输入类的类,在执行时创建一个类,在编译和执行时创建输入类

    什么

    对。假设您有一个包含一些字符串的类,如下所示:

    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"可以在其中找到。现在,您可以更改这些字符串,然后编译并执行这个creator类

    它将使用修改后的字符串创建一个新的ClassContainingStrings.class

  4. # 4 楼答案

    jar文件是类的zip文件,我想你已经明白了。最好的方法是加载一个带有反编译器插件的JavaIDE(非常确定Intellij内置了这个插件)。反编译完成后,可以更改生成的源代码并重新编译

    这不是微不足道的java内容,但也不是那么复杂。如果您以前做过一些java项目开发,那就不难了