Java ASM is an open-source java library for manipulating bytecode.
本项目旨在系统地介绍如何学习Java ASM的知识,主要涉及Core API、OPCODE和Tree API等内容。至于学习的预期目标就是,用一个形象的说法来讲,让字节码在你的手中“跳舞”:看看你的左手,一个完整的ClassFile拆解成不同粒度的字节码内容;看看你的右手,不同粒度的字节码内容又重新组织成一个ClassFile结构。
_______ , _ _
(, /' /'/ /' `\ ' ) _)
/' /' / /' ._) // _/~/'
/'____ . , ____ ,/' / (____ /'/_/~ /'
_ /'/' )| / /' ) /`--,/ ) /' /~ /'
/' ` /'/' /' | /' /' /' /' / /' /' /'
(_____,/' (___,/(___|/(__(___,/(__ (,/' (_,(_____,/'(,/' (_,
如果我们学会了Java ASM之后,可能还是需要一个具体的应用场景来进行使用,这个场景就是由 Java Agent 开启的。
那么,Java ASM和Java Agent这两者之间是什么关系呢? Java ASM是一个操作字节码的工具(tool),而Java Agent提供了修改字节码的机会(opportunity)。 想像这样一个场景: 有一个JVM正在运行,突然Java Agent在JVM上打开一扇大门,Java ASM通过大门冲进JVM里面,就要开始修改字节码了。
.class --- Java ASM --- Java Agent --- JVM
再打个比方,Java ASM就是“一匹千里马”,而Java Agent就是“伯乐”。 如果遇不到“伯乐”,可能“千里马”的才能就埋没了;正因为有了“伯乐”,“千里马”就有了施展才能的机会。
世有伯乐,然后有千里马。
千里马常有,而伯乐不常有。
故虽有名马,祗辱于奴隶人之手,骈死于槽枥之间,不以千里称也。
从Gitee 仓库下载代码,使用如下命令:
git clone https://gitee.com/lsieun/learn-java-asm
从GitHub 仓库下载代码,使用如下命令:
git clone https://github.com/lsieun/learn-java-asm
在learn-java-asm
项目当中,使用的ASM版本为9.0
。如果想使用最新 版本,可以修改pom.xml
文件中的asm.version
属性:
<asm.version>9.0</asm.version>
在learn-java-asm
项目当中,包含main
方法的类主要位于run
包(src/main/java/run
)。
从组成结构上来说,Java ASM有Core API和Tree API两部分组成。
┌─── asm.jar
│
┌─── Core API ─────────┼─── asm-util.jar
│ │
│ └─── asm-commons.jar
Java ASM ───┤
│
│ ┌─── asm-tree.jar
└─── Tree API ─────────┤
└─── asm-analysis.jar
从依赖关系角度上说,Java ASM当中的各个.jar
之间的依赖关系如下:
┌────────────────────────────┬─────────────────────────────┐
│ ┌───────┴────────┐ │
│ util │ analysis │ commons │
│ ┌──────┴────────────────┴──────┐ │
│ │ tree │ │
├─────────────┴──────────────────────────────┴─────────────┤
│ core │
└──────────────────────────────────────────────────────────┘
从应用的角度来说,Java ASM可以进行Class Generation、Class Transformation和Class Analysis三个类型的操作。
┌─── find potential bugs
│
┌─── analysis ─────────┼─── detect unused code
│ │
│ └─── reverse engineer code
│
Java ASM ───┼─── generation
│
│ ┌─── optimize programs
│ │
└─── transformation ───┼─── obfuscate programs
│
└─── insert performance monitoring code
在下表当中,top、null和void三者相对应的转换值:
┌─────────────┬────────────────────────────┬────────────────────────────────┐
│ .class │ ASM Type │ ASM Value in Frame │
├─────────────┼────────────────────────────┼────────────────────────────────┤
│ top │ null │ BasicValue.UNINITIALIZED_VALUE │
├─────────────┼────────────────────────────┼────────────────────────────────┤
│ aconst_null │ BasicInterpreter.NULL_TYPE │ BasicValue.REFERENCE_VALUE │
├─────────────┼────────────────────────────┼────────────────────────────────┤
│ void │ Type.VOID_TYPE │ null │
└─────────────┴────────────────────────────┴────────────────────────────────┘
在编写代码的过程中,会遇到一些Typo提示,原因是insn
等内容不是合法的单词。
解决方法:借助于IntelliJ IDEA的Spellchecking 的功能。
操作步骤:
Settings/Preferences
当中,找到Editor | Natural Languages | Spelling
位置。learn-java-asm
项目根目录下,有一个accepted-words.dic
文件,添加该文件即可。配置完成之后,需要重新启动IntelliJ IDEA才能生效。
在编写代码的过程中,为了方便理解代码,我添加了一些笔记,格式如下:
NOTE: 希望这是一条有用的笔记
但是,在默认情况下,它并不会高亮显示,因此不容易被察觉到。
解决方法:借助于IntelliJ IDEA的TODO comments 功能。
操作步骤:
Settings/Preferences
当中,找到Editor | TODO
位置。\bnote\b.*
配置完成之后,需要重新启动IntelliJ IDEA才能生效。
在默认情况下,运行任何类,都会输出调试信息。在调试信息中,会带有[DEBUG]
标识。
如果想关闭调试信息,可以修改lsieun.cst.Const
类的DEBUG
字段值为false
(默认值为true
):
public class Const {
public static final boolean DEBUG = false;
}
然后,执行mvn clean compile
对类进行重新编译:
mvn clean compile
等待编译完成之后,再次运行程序。
This project is licensed under the MIT License. See the LICENSE file for the full license text.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。