1

我正在尝试生成一个名为 hello 的方法,该方法使用动态字节码生成返回值 2。这是我当前的代码。生成方法。

    dout.writeShort(Modifier.PUBLIC);//class modifier
    dout.writeShort(classConstant("test"));//class name
    dout.writeShort(classConstant(Object.class.getName()));//superclass
    dout.writeShort(0);//interface count
    dout.writeShort(0);//field count
    dout.writeShort(1);//method count
    dout.writeShort(Modifier.PUBLIC|Modifier.STATIC);//modifiers
    dout.writeShort(utfConstant("test"));//name
    dout.writeShort(utfConstant(methodDescriptor(int.class, new Class[]{})));//descriptor
    dout.writeShort(1);//attribute count
    dout.writeShort(utfConstant("Code"));//attribute name
    dout.writeInt(34);//attribute length
    dout.writeShort(1);//max stack
    dout.writeShort(0);//max locals
    dout.writeInt(2);//code length
    dout.writeByte(0x05);//iconst_2 opcode
    dout.writeByte(0xAC);//ireturn opcode
    dout.writeShort(0);//exception count
    dout.writeShort(0);//attribute count
    dout.writeShort(0);//class attributes

问题是当我运行这段代码时,我得到了这个异常

Exception in thread "main" java.lang.ClassFormatError: Invalid method Code length 0 in class file test
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
    at Bytecode.BytecodeTest$BytecodeClassLoader.buildClass(BytecodeTest.java:229)
    at Bytecode.BytecodeTest.makeClass(BytecodeTest.java:42)
    at Bytecode.BytecodeTest.buildClass(BytecodeTest.java:27)
    at Bytecode.BytecodeTest.main(BytecodeTest.java:19)

奇怪的是,我使代码长度大于 0,我将其设置为 2。我回顾了 oracle 规范,但它看起来仍然正确。我有一种感觉,我正在将一些数据写为错误的类型,但我仍然找不到问题。

4

2 回答 2

1

Hotspot 验证程序的一个未记录的特性是,对于 <= 45.2 的版本,它对 code 属性中的某些字段使用较短的字段长度。这就是为什么将版本更改为 49 可以解决所有问题。

如果您使用 Krakatau,它会自动处理此问题,但我还没有看到任何其他工具可以处理这种情况。

幸运的是,Java 的第一个稳定公共版本是 45.3,因此您不太可能在野外看到这样的合法代码。但这是挫败逆向工程师的巧妙技巧。

于 2013-06-25T02:26:20.990 回答
0

好吧,让我印象深刻的一件事是属性长度:据我计算,它应该是 14(而不是 34)。您似乎还缺少类属性计数。

它可能会帮助您定义几个用于编写属性的辅助方法,以确保您正确计算和编写长度,例如,如下所示:

private int writeAttribute(final String attributeName) {
    dout.putShort(utfConstant(attributeName));
    dout.putInt(0);
    return dout.position();
}

private void endAttribute(final int attributeStart) {
    dout.putInt(attributeStart- 4, dout.position() - attributeStart);
}

private void writeCode() {
    final int codeAttributeStart = writeAttribute("Code");

    dout.writeShort(1);//max stack
    dout.writeShort(0);//max locals
    dout.writeInt(2);//code length
    dout.writeByte(0x05);//iconst_2 opcode
    dout.writeByte(0xAC);//ireturn opcode
    dout.writeShort(0);//exception count
    dout.writeShort(0);//attribute count

    endAttribute(codeAttributeStart);
}

此外,请确保您写出的类文件次要/主要版本与您所遵循的规范相匹配——格式确实会不时更改:)。

于 2013-06-24T21:04:04.930 回答