Bạn có thể có một cái nhìn tại Apache BCEL (ByteCode Engineering Library). Nó chứa một lớp học mạnh mẽ đáng chú ý được gọi là BCELifier
. Nó là một lớp có thể lấy một lớp đầu vào, và, khi được thực hiện, tạo ra một lớp, khi được biên dịch và thực thi, tạo ra lớp đầu vào.
Cái gì?
Có. Vì vậy, hãy tưởng tượng bạn có một lớp có chứa một số chuỗi, như thế này:
public class ClassContainingStrings
{
private String someString = "Some string";
public void call()
{
System.out.println("Printed string");
System.out.println(someString);
}
}
Bây giờ, bạn có thể biên dịch này, để có được những tập tin ClassContainingStrings.class
. Tập tin này có thể được đưa vào BCELifier
, như thế này:
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();
}
}
Nó sẽ tạo ra một tập tin gọi ClassContainingStringsCreator.java
. Đối với ví dụ đã cho, điều này sẽ trông giống như sau:
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"));
}
}
(vâng, có vẻ khủng khiếp, nhưng điều đó không quan trọng quá nhiều).Điều quan trọng là các chuỗi từ lớp gốc, cụ thể là chuỗi "Some string"
và "Printed string"
có thể được tìm thấy trong đó. Bây giờ, bạn có thể thay đổi các chuỗi này, sau đó biên dịch và thực thi lớp người tạo này.
Nó sẽ tạo một ClassContainingStrings.class
mới, với các chuỗi đã sửa đổi.
Tôi muốn bắt đầu tìm thông số về định dạng nhị phân của tệp .class và hiểu cách chuỗi được biểu diễn, có thể là trường có kích thước trước chuỗi thực tế, có lẽ ...? – Adam
Thử "Grav Engine Turn OFF/ON" = cùng số byte (chế độ ghi đè). –
@ user265889 Có câu trả lời nào của chúng tôi giải quyết được sự cố của bạn không? – Adam