【我的ASM学习进阶之旅】 01开篇介绍ASM

0x00、简介

ASM名称不代表任何含义:它只是对C语言中__asm__关键字的引用,它允许使用汇编语言实现某些功能

ASM是一个通用的Java字节码操作和分析框架。它可以直接以二进制形式用于修改现有类或动态生成类。

ASM提供了一些常见的字节码转换和分析算法,可以从中构建定制的复杂转换和代码分析工具。

ASM提供与其他Java字节码框架类似的功能,但侧重于性能。
因为它的设计和实现是尽可能的小和尽可能快,所以它非常适合在动态系统中使用(但当然也可以以静态方式使用,例如在编译器中使用)。

在许多项目中都使用ASM,包括:

  • OpenJDK,用于生成lambda调用站点;在Nashorn编译器,
  • Groovy编译器和Kotlin编译器,
  • Cobertura和Jacoco中,ASM还用于检测类,以测量代码覆盖率
  • CGLIB,动态生成代理类(在Mockito和EasyMock等其他项目中使用的代理类)
  • Gradle,以便在运行时生成一些类。

最近的版本: 2020年9月22日:发布ASM 9.0

0x01、动机

程序分析,程序生成和程序转换是可以在许多情况下使用的有用技术:

  • 程序分析
    程序分析的范围从简单的语法分析到完整的语义分析,都可用于查找应用程序中的潜在错误,检测未使用的代码,反向工程代码等。

  • 程序生成
    程序生成在编译器中使用。其中包括传统的编译器,还包括用于分布式编程的stub或者skeleton编译器,即时编译器等。

  • 程序转换
    程序转换可用于优化或混淆程序,将调试或性能监视代码插入应用程序,面向切面(aspect oriented programming)的编程等。

所有上面的这些技术都可以用于任何编程语言,但这或多或少容易实现,具体取决于语言。

对于Java,它们可以在Java源代码或已编译的Java classes上使用。处理已编译的classes的优点之一,很明显就是不需要源代码。因此,程序转换可用于任何应用程序,包括封闭源代码和商业应用程序。

处理已编译代码的另一个优点是,可以在将类加载到Java虚拟机中之前在运行时分析,生成或转换类(可以在运行时生成和编译源代码,但这确实很慢,并且需要完整的Java编译器)。优点是stub编译器或Aspect Weaver等工具对用户透明。

由于程序分析,生成和转换技术的许多可能用法,因此已经为许多语言(包括Java)实现了许多分析,生成和转换程序的工具。

ASM是Java语言的其中一种工具,旨在用于运行时(但也可以脱机)类生成和转换。因此,ASM库被设计为在编译的Java classes上工作。
它还被设计为尽可能快和尽可能小。

  • 为了不减慢在运行时使用ASM的应用程序进行动态类生成或转换的速度,尽可能快是很重要的。
  • 为了在受内存限制的环境中使用,并避免使用ASM减小小型应用程序或库的大小,尽可能小是很重要的。

ASM不是生成和转换已编译Java类的唯一工具,而是最新,最有效的工具之一。
可以从http://asm.objectweb.org下载。
其主要优点如下:

  • 它具有简单易用,设计良好的模块化API。
  • 有据可查,并且具有关联的Eclipse插件。
  • 它提供对最新Java版本Java 7的支持。
  • 它体积小,速度快且功能强大。
  • 其庞大的用户社区可以为新用户提供支持。
  • 其开源许可证允许您以几乎任何所需的方式使用它。

0x02 概述

2.1 范围

ASM库的目标是生成,转换和分析已编译的Java类,它们表示为字节数组(因为它们存储在磁盘上并加载在Java虚拟机中)。

为此,ASM提供了使用比字节更高级别的概念来读取,写入和转换此类字节数组的工具,例如数字常量,字符串,Java标识符,Java类型,Java类结构元素等。

请注意,ASM库的范围严格限于读取classes,写classes,转换classes和分析classes。特别是,类加载过程超出了范围。

2.2 模型

ASM库提供了两个用于生成和转换已编译类的API:

  • core API提供基于事件的classes表示,
  • tree API提供基于对象的表示。
  • 基于事件的模型
    在基于事件的模型中,一个类由一系列事件表示,每个事件代表该类的元素,例如其标题,字段,方法声明,指令等。基于事件的API定义了一组可能的事件事件及其发生的顺序,并提供了一个类解析器,该解析器为每个被解析的元素生成一个事件,以及一个类编写器,该类编写器根据此类事件的序列生成已编译的类。

  • 基于对象的模型
    在基于对象的模型中,用对象树表示一个类,每个对象代表该类的一部分,例如类本身,字段,方法,指令等,每个对象都具有对这些对象的引用。代表其成分。
    基于对象的API提供了一种将表示一个类的事件序列转换为表示相同类的对象树的方法,反之亦然,是一种将对象树转换为等效事件序列的方法。
    换句话说,基于对象的API建立在基于事件的API之上


这两个API可以与XML文档的简单API(SAX)和XML文档的文档对象模型(DOM)API进行比较:

基于事件的API与SAX类似,而基于对象的API与DOM类似。

基于对象的API建立在基于事件的API之上,就像可以在SAX之上提供DOM一样。

ASM提供这两种API,因为没有最好的API。实际上,每个API都有自己的优点和缺点:

  • 与基于对象的API相比,基于事件的API更快并且需要的内存更少,因为不需要创建并在内存中存储代表该类的对象树(SAX和DOM之间也存在相同的区别)
  • 但是,使用基于事件的API实现类转换可能会更加困难,因为在任何给定时间只有该类的一个元素(与当前事件相对应的元素)才可用,而整个类都可以在基于对象的API内存中使用

请注意,这两个API一次仅管理一个类,而与其他API无关:不维护有关类层次结构的信息,并且如果类转换影响其他类,则由用户来修改这些其他类。

2.3 架构

ASM应用程序具有强大的体系结构方面。

实际上,基于事件的API是围绕事件生成器(类解析器),事件使用者(类编写器)和各种预定义的事件过滤器组织的,可以向其中添加用户定义的生产者,使用者和过滤器。因此,使用此API分为两个步骤:

  1. 将事件产生器,过滤器和使用者组件组装到可能复杂的架构中
  2. 然后启动事件生产者以运行生成或转换过程。

基于对象的API也具有体系结构方面:实际上,可以构成对对象树进行操作的类生成器或转换器组件,它们之间的链接表示转换的顺序。

尽管典型ASM应用程序中的大多数组件体系结构都非常简单,但是可以想象如下复杂的体系结构,其中箭头表示类解析器,编写器或转换器之间的基于事件或基于对象的通信,并且可能在基于事件和基于对象之间进行转换 链中任何地方的表示形式:

在这里插入图片描述

0x03 组织

ASM库组织在几个包中,这些包分布在几个jar文件中:

  • org.objectweb.asm和org.objectweb.asm.signature包
    定义基于事件的API,并提供类解析器和编写器组件。 它们包含在asm.jar存档中。

  • 在asm-util.jar档案中的org.objectweb.asm.util包中,
    提供了基于核心API的各种工具,这些工具可以在
    ASM应用程序的开发和调试中使用。

  • org.objectweb.asm.commons包提供了几个有用的预定义类转换器,这些转换器主要基于核心API。 它包含在asm-commons.jar存档中。

  • org.objectweb.asm.tree包,在asm-tree.jar存档中,
    定义基于对象的API,并提供在基于事件的表示和基于对象的表示之间进行转换的工具。

  • org.objectweb.asm.tree.analysis包提供了一个基于树API的类分析框架和几个预定义的类分析器。 它包含在asm-analysis.jar存档中。

接下来的数篇博客分为两部分介绍ASM。
第一部分介绍了核心API,即 asm,asm-util和asm-commons档案。
第二部分介绍了树API,即asm-tree和asm-analysis存档。

这种组织结构使逐步引入类文件功能变得更加容易,但有时需要将单个ASM类的表示形式分散在几个部分中。 因此,建议按顺序阅读本文档。 有关ASM API的参考指南,请使用Javadoc

0x04 版本

ASM发布的相关版本,查看链接Versions

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章