美文网首页
JVM 字节码操作 ASM 框架简单讲解

JVM 字节码操作 ASM 框架简单讲解

作者: YUNDONG丶 | 来源:发表于2019-10-22 14:01 被阅读0次
什么是 ASM ?

ASM 是一款直接操作字节码(即 class 文件)的框架,可以都已生成好的字节码进行改动或者生成。类似框架有 javassist 相对 ASM 简单许多。

谁在用 ASM ?

大名鼎鼎的 FastJSON & CGLIB

说在前面

官网 API 文档
网上关于 ASM 都是一些零散的资料,框架本事并不是很难。但是要彻底学习需要一段时间。建议理解就好。日常工作基本上不会使用。

字节码操作

众所周知 .java 文件经过,javac 的编译后会生成一个后缀为 .class 的字节码文件。而这个文件才是 JVM 要真正读取运行的文件。而这个 .class 文件是一个可编辑的文件。你使用任何一个文本编辑都可以看到以下内容

image.png

你可以通过开头的 cafe babe 认定他是一个 .class 文件。关于字节码的解读网上资料较多你可以百度一下

手动修改字节码

上方字节码源码如下:

public class Hello{
    public static void main(String[] args) {
        int i =  8888;
        System.out.print(i);
    }
}

我们都知道如果使用 java Hello 运行上方编译过后的 .class 文件会输出 8888

我们回过头再是观察上方字节码会发现 .class 文件是由 16进制 组成的。我们通过 进制转换工具8888 转换成16进制就是 22b8


然后在编译后的文件找到 22b8
替换成 270f(转换为10进制为 9999 ) 再使用 java Hello 运行(不要再使用 javac 编译)得出结果:
手动修改字节码码就成功了。
通过 ASM 修改字节码。
  1. ASM 有两种修改字节码的方式

流 和 树。
流:一边读取 class 文件一边修改。
树:全部读取出来,选择任意节点修改。

  1. ASM 中的部分修改并不是真正的修改。例如:

你打算通过 ASM 修改一个方法的返回值。ASM 会重建这个方法。把之前的删除掉。

  1. ASM 有三个重要的类

ClassReader:读取 class 文件转换成的 byte 数组
ClassVisitor & ClassNode:分别对应 流 & 树 中字节码操作类
ClassWriter:将处理好的 class 文件转换成 byte 数组

演示,因为代码有点多。完整的代码前往 github

ASM 中创建一个方法

我们先要获取这个类的 class 文件,然后转成 byte 数组

package com.annie.util;
import com.annie.App;
import java.io.*;
public class FileUtil {
    // 将 class 文件转成 byte 数组(就是下方 MyMain 实体类编译后的 class 文件位置)
    public static byte[] File2Byte() throws IOException {
        // 获取 class 文件所在的位置
        String path = App.getMyMainPath();
        File file = new File(path);
        byte[] bytes = new byte[(int) file.length()];
        try (FileInputStream fileInputStream = new FileInputStream(file);) {
            fileInputStream.read(bytes);
        }
        return bytes;
    }
    // 将 byte 数组写进 class 文件
    public static boolean Byte2File(byte[] bytes) throws IOException {
        String path = App.getMyMainPath();
        File file = new File(path);
        try (FileOutputStream fileOutputStream = new FileOutputStream(file);) {
            fileOutputStream.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

新建一个实体类

// 类中有 两个参数 五个方法
class MyMain {
    int i = 1;
    int j = 2;

    public void t01() {

    }
    public void t02(String str) {

    }

    public String t03() {

        return "hello";
    }

    public String t04(String str) {


        return str;
    }

    public int t05(int i) {

        return i;
    }
}

编写添加属性的方法

public static void createField() throws IOException {
        byte[] bytes = FileUtil.File2Byte();

        // 读取 byte 数组
        ClassReader cr = new ClassReader(bytes);

        // 创建一个树节点
        ClassNode cn = new ClassNode();

        // 将 cr 转换好的字节码放进 cn 树中
        // SKIP_DEBUG 跳过类文件中的调试信息,比如行号信息(LineNumberTable)等
        // SKIP_CODE:跳过方法体中的 Code 属性(方法字节码、异常表等)
        cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);

        // 新建一个属性
        // 参数作用域,参数名称,参数类型,参数签名,参数初始值
        FieldNode fn = new FieldNode(Opcodes.ACC_PUBLIC, "code", "Ljava/lang/String;", null, null);

        // 将属性添加到 cn 参数节点中
        cn.fields.add(fn);

        // 再 JVM 存在,数栈和局部变量表
        // new ClassWriter(0):表示我们手动设置。(这里我们用不到)
        ClassWriter cw = new ClassWriter(0);

        // 将新生成的 'class' 放进 cw 中
        cn.accept(cw);

        // cw 将新的 'class' 处理成byte覆盖之前原始的class文件
        FileUtil.Byte2File(cw.toByteArray());
    }

然后通过观察项目中的 MyMain.class 文件会发现。


你会发现多了一个 code 属性。我这是使用的是 idea 进行的反编译。只将 .class 文件拖进 idea 中就行。使用 javap -l MyMain.class 一样可以达到效果。
说在后面的话,

再博客中可能演示的不是那么仔细。如果有兴趣可以去github上下载一分代码看一下。关键的还是要多看官网 API 文档说白了。ASM 也就是一个类而已,和我们平时用的 HTTP IO 也差不了多少。只是领域不同。

ASM 能做什么?
Java 序列的软件破解。JavaAgent 技术等。

结尾:如果您觉得这边文章对您有帮助,麻烦\color{red}{点赞}\color{red}{评论}\color{red}{评论}。您的支持是对笔者的最大帮助😘😘😘

扩展内容
github
个人博客

相关文章

  • JVM 字节码操作 ASM 框架简单讲解

    什么是 ASM ? ASM 是一款直接操作字节码(即 class 文件)的框架,可以都已生成好的字节码进行改动或者...

  • Spring 源码分析之一:Spring Core模块详解

    先上图: Core模块在整个框架中的地位,就是地基,主要包含: 1、asm:字节码框架,能动态改变jvm里面的字节...

  • 奇门遁甲之字节码与JVM指令

    最近在研究ASM 字节码增强技术,要掌握ASM 必须要先连接Java字节码结构、JVM栈帧和常用JVM指令。 本章...

  • ASM

    ASM 是什么? ASM 是一个十分强大的字节码处理框架,基本上可以实现对字节码的任何操作,但是需要对 Java ...

  • ASM字节码插桩详解

    1、ASM概述 ASM是一个功能比较齐全的java字节码操作与分析框架,通过ASM框架,我们可以动态的生成类或者增...

  • Android ASM字节码插桩(上)

    一、ASM简介ASM是一个字节码操作框架,可用来动态生成字节码或者对现有的类进行增强。ASM可以直接生成二进制的c...

  • 43 AOP(面向切面编程)-ASM-2

    1. ASM 介绍 ASM 是一个 Java 字节码操作框架,它能用来动态生成类或者增强既有类的功能。ASM 可以...

  • 奇门遁甲之ASM操纵字节码

    本文记录对ASM 字节码操控框架的梳理和总结,方便需要时查看。 一、什么是ASM ASM 是一个 Java 字节码...

  • 史上最全的ASM原理解析与应用

    ASM简介 ASM是一个操作Java字节码类库,其操作的对象是字节码数据,处理字节码方式是“拆分-修改-合并”将....

  • JavaAgent 与 动态代理

    ASM, CGlib, Java Proxy, Javassist都是可以操作字节码,但是这些操作字节码都需要等到...

网友评论

      本文标题:JVM 字节码操作 ASM 框架简单讲解

      本文链接:https://www.haomeiwen.com/subject/kfxqvctx.html