簡體   English   中英

如何使用 ASM 4.0 修改 Java 字節碼

[英]How to modify a Java bytecode using ASM 4.0

我是 ASM 框架的新手。 我已經圍繞這個 ASM 框架工作了一個星期。 我在網上看到了關於解析類和從頭生成 .class 文件的教程。 但是我無法了解如何修改 ASM 中的現有類。

我無法遵循ClassVisitorClassWriterClassReader之間的執行流程。

請通過為我提供以下代碼的 ASM 示例來解決我的問題。

public class ClassName {
  public void showOne() {
    System.out.println("Show One Method");
  }

  public static void main(String[] args) {
    ClassName c = new ClassName();
    c.showOne();
  }
}

上面的類應該修改為:

public class ClassName {
  public void showOne() {
    System.out.println("Show One Method");
  }

  public void showTwo() { // <- Newly added method
    System.out.println("Show Two Method");
  }

  public static void main(String[] args) {
    ClassName c = new ClassName();
    c.showOne();
    c.showTwo(); // <- Newly inserted method call
  }
}

修改它的ASM代碼應該是什么?

我使用了 ASMifier 工具來生成代碼。 但我不知道在哪里應用它。

你的要求有點不明確。 下面是一個示例程序,它使用 ASM 的訪問者 API 將假定具有您的問題結構的類轉換為結果類。 我添加了一個使用字節數組並返回一個字節數組的便捷方法。 這種方法可以在兩種情況下使用,靜態轉換應用於磁盤上的類文件以及 Instrumentation 代理。

ClassWriter與傳遞給ClassReaderClassVisitor組合在一起時,如下所示,它將自動復制源類的每個功能,因此您只需覆蓋要應用更改的這些方法。

在這里, visitMethod被重寫以在遇到修改它的main方法時進行攔截,而visitEnd被重寫以附加全新的showTwo方法。 MainTransformer將攔截RETURN指令(在您的示例中應該只有一個)以在它之前插入對showTwo的調用。

import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter;

public class MyTransformer extends ClassVisitor {

  public static byte[] transform(byte[] b) {
    final ClassReader classReader = new ClassReader(b);
    final ClassWriter cw = new ClassWriter(classReader,
      ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
    classReader.accept(new MyTransformer(cw), ClassReader.EXPAND_FRAMES);
    return cw.toByteArray();
  }

  public MyTransformer(ClassVisitor cv) {
    super(Opcodes.ASM5, cv);
  }
  @Override
  public MethodVisitor visitMethod(int access, String name, String desc,
      String signature, String[] exceptions) {

    MethodVisitor v=super.visitMethod(access, name, desc, signature, exceptions);
    if(name.equals("main") && desc.equals("([Ljava/lang/String;)V"))
      v=new MainTransformer(v, access, name, desc, signature, exceptions);
    return v;
  }
  @Override
  public void visitEnd() {
    appendShowTwo();
    super.visitEnd();
  }
  private void appendShowTwo() {
    final MethodVisitor defVisitor = super.visitMethod(
      Opcodes.ACC_PUBLIC, "showTwo", "()V", null, null);
    defVisitor.visitCode();
    defVisitor.visitFieldInsn(Opcodes.GETSTATIC,
      "java/lang/System", "out", "Ljava/io/PrintStream;");
    defVisitor.visitLdcInsn("Show Two Method");
    defVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
      "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
    defVisitor.visitInsn(Opcodes.RETURN);
    defVisitor.visitMaxs(0, 0);
    defVisitor.visitEnd();
  }
  class MainTransformer extends GeneratorAdapter
  {
    MainTransformer(MethodVisitor delegate, int access, String name, String desc,
        String signature, String[] exceptions) {
      super(Opcodes.ASM5, delegate, access, name, desc);
    }
    @Override
    public void visitInsn(int opcode) {
      if(opcode==Opcodes.RETURN) {
        // before return insert c.showTwo();
        super.visitVarInsn(Opcodes.ALOAD, 1); // variable c
        super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
            "ClassName", "showTwo", "()V", false);
      }
      super.visitInsn(opcode);
    }
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM