【问题标题】:Modifiying <clinit> with ASM使用 ASM 修改 <client>
【发布时间】:2016-06-10 13:10:46
【问题描述】:

您好,我对 ASM 有一点问题。它产生一个字节码错误的类:

Exception in thread "main" java.lang.VerifyError: Bad instruction
Exception Details:
  Location:
    me/test/Main.<clinit>()V @0: wide
  Reason:
    Error exists in the bytecode

    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
    at java.lang.Class.privateGetMethodRecursive(Unknown Source)
    at java.lang.Class.getMethod0(Unknown Source)
    at java.lang.Class.getMethod(Unknown Source)
    at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
    at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

当我使用以下代码将代码注入&lt;clinit&gt; 方法时,该方法用“key”(byte[])变量填充静态字节数组:

   if (key.length > 128)
        this.visitVarInsn(SIPUSH, key.length);
    else
        this.visitVarInsn(BIPUSH, key.length);
    this.visitVarInsn(NEWARRAY, 8);
    for (int i = 0; i < key.length; i++) {
        this.visitInsn(DUP);
        if (i > 127) {
            this.visitVarInsn(SIPUSH, i + 32768);
        } else if (i < 6) {
            switch (i) {
                case 0:
                    this.visitInsn(ICONST_0);
                    break;
                case 1:
                    this.visitInsn(ICONST_1);
                    break;
                case 2:
                    this.visitInsn(ICONST_2);
                    break;
                case 3:
                    this.visitInsn(ICONST_3);
                    break;
                case 4:
                    this.visitInsn(ICONST_4);
                    break;
                case 5:
                    this.visitInsn(ICONST_5);
                    break;
                default:
                    System.out.println("Logic mistake!");
                    break;
            }
        }
        else {
            this.visitVarInsn(BIPUSH, i);
        }
        if (key[i] < 6 && key[i] >= 0) {
            switch (key[i]) {
                case 0:
                    this.visitInsn(ICONST_0);
                    break;
                case 1:
                    this.visitInsn(ICONST_1);
                    break;
                case 2:
                    this.visitInsn(ICONST_2);
                    break;
                case 3:
                    this.visitInsn(ICONST_3);
                    break;
                case 4:
                    this.visitInsn(ICONST_4);
                    break;
                case 5:
                    this.visitInsn(ICONST_5);
                    break;
                default:
                    System.out.println("Logic mistake!");
                    break;
            }
        } else {
            this.visitVarInsn(BIPUSH, key[i]);
        }
        this.visitInsn(BASTORE);

【问题讨论】:

  • @Holger 密钥始终为 2048 字节。我会检查 32768 的东西
  • @Holger 这搞砸了...我删除了 +32768 并且发生了这种情况:原始字节码:pastebin.com/5Rr85SpS 修改后的字节码:pastebin.com/sg0yLTgb

标签: java java-bytecode-asm


【解决方案1】:

您的代码不正确的主要原因是您多次滥用visitVarInsn。

visitVarInsn 设计用于参数是局部变量索引的指令。由于它取决于特定指令,参数如何编码到指令中,当与指令一起使用时,此方法会产生不正确的代码,它不是为之设计的。所以,而不是

this.visitVarInsn(NEWARRAY, 8);

你应该使用

this.visitIntInsn(NEWARRAY, Opcodes.T_BYTE);

这同样适用于 this.visitVarInsn(SIPUSH, key.length); 和 this.visitVarInsn(BIPUSH, key.length); 的错误调用,但在这些情况下,您的重复代码中会出现其他错误,例如正确的你的第一次出现,

if (key.length > 128)
    this.visitVarInsn(SIPUSH, key.length);
else
    this.visitVarInsn(BIPUSH, key.length);

当常量值正好是128 时会中断。此外,this.visitVarInsn(SIPUSH, i + 32768); 包含一个虚假的+ 32768 以及使用错误的方法。

通常,您不应重复此代码来生成最佳指令。要么创建一个实用方法,您只需证明其正确性一次,要么使用现有方法。例如,如果您从InstructionAdapter 继承而不是直接从MethodVisitor 继承,则可以使用iconst(int),它将自动生成ICONST_x、BIPUSH、SIPUSH 或LDC。或者,当您从 GeneratorAdapter 继承时,您可以使用 push(int) 来实现相同的效果。

所以使用GeneratorAdapter,代码就这么简单

push(key.length);
newArray(Type.BYTE_TYPE);
for(int i = 0; i < key.length; i++) {
    this.visitInsn(Opcodes.DUP);
    push(i);
    push(key[i]);
    visitInsn(Opcodes.BASTORE);
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-29
相关资源
最近更新 更多