我试图修改一个将#Gra;引力引擎关闭/打开的Minecraft mod(gravisuite)"每当我按F键,但是我想改变这个字符串,我开始更换" Gravitation Engine OFF"随着"引力引擎关闭"通过使用十六进制编辑器,但之后文件不再有效:/我尝试使用像jbe和cjbe和rej这样的工具,并且该字符串在常量池中,但它只会让我删除它...
有没有办法在不破坏它的情况下更改已编译的java类中的字符串?
由于
答案 0 :(得分:2)
我通过一次小调整编译了同一个班级,首先是“foo”,然后是“foo-bar”
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 |........|
用“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 |............|
似乎长度也在结构中编码。请注意3和7 ......有more information on this structure
如果字符串为300个字符,则前两个字节为01 2c。
所以鉴于“万有引力关闭”是29个字符长,我确保你把字符串前面的字节改为1D,它当前应该是19(“引力引擎关闭/开启”时为25个字符)< / p>
答案 1 :(得分:1)
您可以查看Apache BCEL (ByteCode Engineering Library)。它包含一个非常强大的类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
。
答案 2 :(得分:0)
一个jar文件是一个类的zip文件,我猜你已经知道了。你最好的方法是加载一个带有反编译器插件的java IDE(非常确定Intellij内置了这个)。一旦进行了反编译,您就可以更改生成的源并重新编译它。
这不是简单的java东西,但它也不是那么复杂。如果你之前做过一些java项目开发并不那么难。
答案 3 :(得分:0)
文件有校验和:
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