ASM 字节码增强框架详解(下)

简介: ASM是Java中比较流行的用来读写字节码的类库,用来基于字节码层面对代码进行分析和转换。 ASM是一个Java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。 ASM可以直接产生二进制class文件,也可在类被加载入虚拟机之前动态改变类行为, ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能根据要求生成新类。目前许多框架如cglib、Hibernate、 Spring都直接或间接使用ASM操作字节码。

ASM 开发

IDEA使用插件 asm outline 查看 asm 如何生成该类。

image.png

类实现

image.png

对应的 asm 编程代码

package asm.com.javaedge.asm;
import java.util.*;
import org.objectweb.asm.*;
public class TestAsmDump implements Opcodes {
    public static byte[] dump() throws Exception {
        ClassWriter cw = new ClassWriter(0);
        FieldVisitor fv;
        MethodVisitor mv;
        AnnotationVisitor av0;
        cw.visit(52, ACC_PUBLIC + ACC_SUPER, "com/javaedge/asm/TestAsm", null, "java/lang/Object", null);
        cw.visitSource("TestAsm.java", null);
        {
            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(7, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "Lcom/javaedge/asm/TestAsm;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
            mv.visitCode();
            Label l0 = new Label();
            Label l1 = new Label();
            Label l2 = new Label();
            mv.visitTryCatchBlock(l0, l1, l2, "java/lang/InterruptedException");
            Label l3 = new Label();
            mv.visitLabel(l3);
            mv.visitLineNumber(10, l3);
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Hello ASM");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            mv.visitLabel(l0);
            mv.visitLineNumber(12, l0);
            mv.visitLdcInsn(new Long(100L));
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "sleep", "(J)V", false);
            mv.visitLabel(l1);
            mv.visitLineNumber(15, l1);
            Label l4 = new Label();
            mv.visitJumpInsn(GOTO, l4);
            mv.visitLabel(l2);
            mv.visitLineNumber(13, l2);
            mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/InterruptedException"});
            mv.visitVarInsn(ASTORE, 1);
            Label l5 = new Label();
            mv.visitLabel(l5);
            mv.visitLineNumber(14, l5);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/InterruptedException", "printStackTrace", "()V", false);
            mv.visitLabel(l4);
            mv.visitLineNumber(16, l4);
            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            mv.visitInsn(RETURN);
            Label l6 = new Label();
            mv.visitLabel(l6);
            mv.visitLocalVariable("e", "Ljava/lang/InterruptedException;", null, l5, l4, 1);
            mv.visitLocalVariable("this", "Lcom/javaedge/asm/TestAsm;", null, l3, l6, 0);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }
        cw.visitEnd();
        return cw.toByteArray();
    }
}

看看最简单的统计方法执行时间

            ...
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
            mv.visitVarInsn(LSTORE, 1);
            ...
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Hello ASM");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            mv.visitLabel(l0);
            mv.visitLineNumber(13, l0);
            mv.visitLdcInsn(new Long(100L));
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "sleep", "(J)V", false);
            mv.visitLabel(l1);
            mv.visitLineNumber(16, l1);
            Label l5 = new Label();
            mv.visitJumpInsn(GOTO, l5);
            mv.visitLabel(l2);
            mv.visitLineNumber(14, l2);
            mv.visitFrame(Opcodes.F_FULL, 2, new Object[]{"com/javaedge/asm/TestAsm", Opcodes.LONG}, 1, new Object[]{"java/lang/InterruptedException"});
            mv.visitVarInsn(ASTORE, 3);
            Label l6 = new Label();
            mv.visitLabel(l6);
            mv.visitLineNumber(15, l6);
            mv.visitVarInsn(ALOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/InterruptedException", "printStackTrace", "()V", false);
            mv.visitLabel(l5);
            mv.visitLineNumber(17, l5);
            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
            mv.visitVarInsn(LSTORE, 3);
            Label l7 = new Label();
            mv.visitLabel(l7);
            mv.visitLineNumber(18, l7);
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
            mv.visitInsn(DUP);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
            mv.visitLdcInsn("m\u65b9\u6cd5\u6267\u884c\u65f6\u95f4: ");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
            mv.visitVarInsn(LLOAD, 3);
            mv.visitVarInsn(LLOAD, 1);
            mv.visitInsn(LSUB);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            Label l8 = new Label();
            mv.visitLabel(l8);
            mv.visitLineNumber(19, l8);
            mv.visitInsn(RETURN);
            Label l9 = new Label();
            mv.visitLabel(l9);
            mv.visitLocalVariable("e", "Ljava/lang/InterruptedException;", null, l6, l5, 3);
            mv.visitLocalVariable("this", "Lcom/javaedge/asm/TestAsm;", null, l3, l9, 0);
            mv.visitLocalVariable("start", "J", null, l4, l9, 1);
            mv.visitLocalVariable("end", "J", null, l7, l9, 3);
            mv.visitMaxs(6, 5);
            mv.visitEnd();
        }
        cw.visitEnd();
        return cw.toByteArray();
    }
}

这样我们就知道之后用 ASM 编程该加哪些代码了。

目录
相关文章
|
11月前
|
安全 算法 Java
从零开发基于ASM字节码的Java代码混淆插件XHood
因在公司负责基础框架的开发设计,所以针对框架源代码的保护工作比较重视,之前也加入了一系列保护措施,例如自定义classloader加密保护,授权license保护等,但都是防君子不防小人,安全等级还比较低,经过调研各类加密混淆措施后,决定自研混淆插件,自主可控,能够贴合实际情况进行定制化,达到框架升级后使用零感知,零影响
115 1
从零开发基于ASM字节码的Java代码混淆插件XHood
|
4月前
|
Java API Android开发
ASM 框架:字节码操作的常见用法(生成类,修改类,方法插桩,方法注入)
ASM 框架:字节码操作的常见用法(生成类,修改类,方法插桩,方法注入)
76 0
|
4月前
|
存储 算法 Java
ASM字节码操纵框架实现AOP
ASM字节码操纵框架实现AOP
40 0
|
4月前
|
存储 算法 Java
Android 进阶——代码插桩必知必会&ASM7字节码操作
Android 进阶——代码插桩必知必会&ASM7字节码操作
179 0
|
4月前
|
Java Kotlin
ASM字节码插桩实现点击防抖
ASM字节码插桩实现点击防抖
32 0
|
存储 监控 Java
字节码插桩(三): ASM 字节码插桩(1)
字节码插桩(三): ASM 字节码插桩
238 0
字节码插桩(三): ASM 字节码插桩(1)
|
存储 算法 Java
一起来学字节码插桩:ASM Tree API
`ASM`是一个通用的`Java字节码操作和分析框架`。它可用于`修改现有类`或`直接以二进制形式动态生成类`。`ASM`提供了一些常见的字节码转换和分析算法,可以根据这些算法构建定制的复杂转换和代码分析工具。
264 0
|
Java API 开发工具
字节码插桩(三): ASM 字节码插桩(2)
字节码插桩(三): ASM 字节码插桩(2)
135 0
|
Java fastjson 数据库连接
字节码操作框架介绍与实践(以ASM和Javassit为例)
ASM是java字节码操作领域公认的标准,被众多知名的开源框架使用,如cglib、mybatis,fastjson等。通过ASM提供的API,我们可以方便的修改类文件的字节码,并ASM会自动帮我们做很多事情,如维护常量池的索引、计算栈大小max_stack,局部变量表大小max_locals等。ASM提供了两种类型的API,基于事件触发的core api和基于对象的tree api,下面主要介绍基
1225 0
字节码操作框架介绍与实践(以ASM和Javassit为例)
|
5月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
257 2