无法生成代码属性

时间:2013-06-24 14:44:37

标签: java bytecode bytecode-manipulation

我正在尝试生成一个名为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规范,但它仍然看起来正确。我有一种感觉,我把一些数据写成错误的类型,但我仍然无法找到问题。

2 个答案:

答案 0 :(得分:1)

Hotspot验证程序的未记录功能是,对于版本< = 45.2,它对代码属性中的某些字段使用较短的字段长度。这就是为什么将版本更改为49修复所有内容。

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

幸运的是,第一个稳定的Java公共版本是45.3,所以你不太可能在野外看到这样的合法代码。但这对于阻止逆向工程师来说是一个巧妙的伎俩。

答案 1 :(得分: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);
}

另外,请确保您写出的 classfile minor / major version 符合您所遵循的规范 - 格式会不时更改:)。