我是靠谱客的博主 激动花瓣,这篇文章主要介绍asmtools的使用,现在分享给大家,希望可以做个参考。

1. 关于asmtools.jar

用途:使得 “.class文件 -> 字节码指令(类似汇编语言)文件 -> .class文件”,并可以修改“字节码指令文件” 改变一个“.class文件”的运行结果。并重新生成class文件

2. 获取方式asmtools.jar

环境准备:JDK version 8.0, Ant version 1.8 or later, mercurial

下载:hg clone http://hg.openjdk.java.net/code-tools/asmtools
编译:cd asmtools/build && ant 上面是下载打包方式,如果图懒省事,直接使用别人打包好的即可:

3. 使用案例

以郑雨迪老师在“深入拆解JVM”专栏https://time.geekbang.org/column/article/11289 中对boolean类型在jvm中的类型为例示例如何使用:

复制代码
1
2
3
4
5
6
7
8
public class Foo { public static void main(String[] args) { boolean flag = true; if (flag) System.out.println("Hello, Java!"); if (flag == true) System.out.println("Hello, JVM!"); } }

javac Foo.java 命令生成 Foo.class 文件, java Foo 命令运行 Foo.class 文件输出结果:

复制代码
1
2
3
Hello, Java! Hello, JVM!
由 class 文件生成 jasm 文件

如下命令将 class 文件中的内容转换为对应的 jasm 语法

复制代码
1
2
java -jar asmtools.jar jdis Foo.class

执行结果为:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package foo; super public class Foo version 52:0 { public Method "<init>":"()V" stack 1 locals 1 { aload_0; invokespecial Method java/lang/Object."<init>":"()V"; return; } public static Method main:"([Ljava/lang/String;)V" stack 2 locals 2 { iconst_1; istore_1; iload_1; ifeq L14; getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; ldc String "Hello, Java!"; invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; L14: stack_frame_type append; locals_map int; iload_1; iconst_1; if_icmpne L27; getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; ldc String "Hello, JVM!"; invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; L27: stack_frame_type same; return; } } // end Class Foo

可以到看到boolean在JVM实际上是作为int处理的
iconst_1 将1压入操作数栈
istore_1 将操作数栈顶保存至局部变量表1位置,
iload_1 再讲局部变量表1 位置加载到操作数栈顶
ifeq L14 判断栈顶位置是否为0 为零则跳转到L14

我们来尝试修改 将压入的1 改为2 看看什么效果
linux下java -jar asmtools.jar jdis Foo.class > Foo.jasm将上述结果输出到文件中。window下直接新建文件将上一个命令输出结果内容拷贝过去即可
将 Foo.class 中的 int i = 1; 修改成 int i = 2;,我们只需要替换 Foo.jasm 文件中的 iconst_1 为 iconst_2

由jsam文件生成class文件

将修改过后的Foo.jasm 执行命令生成class文件

复制代码
1
2
java -jar asmtools.jar jasm Foo.jasm

此时再执行 java Foo 输出:

复制代码
1
2
Hello, Java!

可见字节码已经被修改,至于为何第一个位false第二个为true,解释为:
ifeq 指令的逻辑是 判断栈顶元素是否为0 不为零纪委true了所以改为2 依然为true。
if_cmpne做整数比较,iconst_1是否等于flag(1)比较失败。

扩展
复制代码
1
2
3
4
5
6
7
8
9
10
public class Foo { static boolean boolValue; public static void main(String[] args) { boolValue = true; // 将这个true替换为2或者3,再看看打印结果 if (boolValue) System.out.println("Hello, Java!"); if (boolValue == true) System.out.println("Hello, JVM!"); } }

结果:
当替换为2的时候无输出
当替换为3的时候打印HelloJava及HelloJVM
是因为将boolean 保存在静态域中,指定了其类型为’Z’,当修改为2时取低位最后一位为0,当修改为3时取低位最后一位为1
则说明boolean的掩码处理是取低位的最后一位

4.总结

主要就两条命令
由 class 文件生成 jasm 文件:java -jar asmtools.jar jdis Foo.class > Foo.jasm
由 jasm 文件生成 class 文件:java -jar asmtools.jar jasm Foo.jasm

最后

以上就是激动花瓣最近收集整理的关于asmtools的使用的全部内容,更多相关asmtools内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(95)

评论列表共有 0 条评论

立即
投稿
返回
顶部