首页 > 其他分享 >ASM插桩

ASM插桩

时间:2023-03-04 09:33:05浏览次数:24  
标签:插桩 InjectTest System long class currentTimeMillis public ASM

使用流程:

1:引入依赖:

implementation 'org.ow2.asm:asm:7.1'
implementation 'org.ow2.asm:asm-commons:7.1'

 

2:想要通过字节码插入代码,使所有的InjectTest方法都加上这两行代码:

long startTime = System.currentTimeMillis();
long endTime = System.currentTimeMillis();
public class InjectTest {
    public InjectTest(){

    }

    public static void main(String[] args) throws InterruptedException {
        //long startTime = System.currentTimeMillis();
        Thread.sleep(3000L);
        //long endTime = System.currentTimeMillis();
    }

    void method(){
        //long startTime = System.currentTimeMillis();

//long endTime = System.currentTimeMillis(); } }

 

3:通过Javac InjectTest.java,生成InjectTest.class,再通过Java p -c InjectTest.class,生成字节码文件

public class com.example.jvm.InjectTest {
  public com.example.jvm.InjectTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: ldc2_w        #3                  // long 3000l
       7: invokestatic  #5                  // Method java/lang/Thread.sleep:(J)V
      10: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      13: lstore_3
      14: return

  void method();
    Code:
       0: return
}

 

4:执行以下代码,生成一个替代文件InjectTest2.class:

public class ASMUnitTest {

    public static void main(String[] args) {
        try {
            FileInputStream fileInputStream = new FileInputStream("F:\\Project\\Practice\\Hencoder\\jvm\\src\\main\\java\\com\\example\\jvm\\InjectTest.class");
            //获取一个分析器
            ClassReader classReader = new ClassReader(fileInputStream);
            ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

            // 开始插桩
            classReader.accept(new MyClassVisitor(Opcodes.ASM7, classWriter), ClassReader.EXPAND_FRAMES);

            byte[] bytes = classWriter.toByteArray();
            FileOutputStream fileOutputStream = new FileOutputStream("F:\\Project\\Practice\\Hencoder\\jvm\\src\\main\\java\\com\\example\\jvm\\InjectTest2.class");

            fileOutputStream.write(bytes);

            fileOutputStream.close();
            fileInputStream.close();

        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 用来访问类的信息
     */
    static class MyClassVisitor extends ClassVisitor{

        public MyClassVisitor(int api) {
            super(api);
        }

        public MyClassVisitor(int api, ClassVisitor classVisitor) {
            super(api, classVisitor);
        }

        /**
         * 每读取到一个方法,都会执行这个api
         */
        @Override
        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
            MethodVisitor methodVisitor = super.visitMethod(access, name,descriptor,signature, exceptions);
            return new MyMethodVisitor(api, methodVisitor, access, name, descriptor);
        }
    }

    static class MyMethodVisitor extends AdviceAdapter {
        /**
         * Constructs a new {@link AdviceAdapter}.
         *
         * @param api           the ASM API version implemented by this visitor. Must be one of {@link
         *                      Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
         * @param methodVisitor the method visitor to which this adapter delegates calls.
         * @param access        the method's access flags (see {@link Opcodes}).
         * @param name          the method's name.
         * @param descriptor    the method's descriptor (see {@link Type Type}).
         */
        protected MyMethodVisitor(int api, MethodVisitor methodVisitor, int access, String name, String descriptor) {
            super(api, methodVisitor, access, name, descriptor);
        }

        /**
         * 方法进去的时候
         */
        int s;
        @Override
        protected void onMethodEnter() {
            super.onMethodEnter();
            //0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
            //是对象,以L开头,以分号结束,()代表的是无参的,J代表的是long类型
            invokeStatic(Type.getType("Ljava/lang/System;"),new Method("currentTimeMillis", "()J"));

            //3: lstore_1
            s = newLocal(Type.LONG_TYPE);
            storeLocal(s);
        }

        /**
         * 方法退出的时候
         */
        @Override
        protected void onMethodExit(int opcode) {
            super.onMethodExit(opcode);
           // 10: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
            //13: lstore_3

        }
    }
}

 生成的InjectTest2.class文件,把这个InjectTest2.class替换原先的InjectTest.class达到热修复的效果。

public class InjectTest {
    public InjectTest() {
        long var1 = System.currentTimeMillis();
    }

    public static void main(String[] var0) throws InterruptedException {
        long var1 = System.currentTimeMillis();
        Thread.sleep(3000L);
        long var5 = System.currentTimeMillis();
    }

    void method() {
        long var1 = System.currentTimeMillis();
        long var5 = System.currentTimeMillis();
    }
}

 

标签:插桩,InjectTest,System,long,class,currentTimeMillis,public,ASM
From: https://www.cnblogs.com/wnpp/p/17177611.html

相关文章