1

動的バイトコード生成を使用して値 2 を返す hello という名前のメソッドを生成しようとしています。これが私の現在のコードです。メソッドを生成します。

    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

1 つ気になったのは、属性の長さです。私の計算では、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 に答える