说明:

在学习极客时间——《深入拆解JVM虚拟机》专栏中,有用到asmtools这样一个工具,用以修改class文件。

一.获取工具

获取工具方法:

  1. 自己构建asmtools.jar:https://www.cnblogs.com/yelongsan/p/9674723.html

  2. 直接下载asmtools.jar:https://yun.515code.com/blog/source/posts/asmtools工具/asmtools.jar

另外,下载 JD-GUI ,它是".class"文件的反编译工具。

拿到jar包后,我们进入命令行即可。

二.测试

1.生成一个java文件,名字为 Foo.java

1
2
3
4
5
6
7
8
echo '
public class Foo {
public static void main(String[] args) {
boolean boolValue = true;
if (boolValue) System.out.println("Hello, Java!");
if (boolValue == true) System.out.println("Hello, JVM!");
}
}' > Foo.java

2.编译并执行

1
2
3
4
5
6
javac Foo.java
java Foo

# 输出结果
Hello, Java!
Hello, JVM!

3.将class文件转换为jasm文件

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
# 转换为 Foo.jasm 文件
java -jar asmtools.jar jdis Foo.class > Foo.jasm

# 文件内容如下
super public class Foo
version 55: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; # 此处修改为 iconst_2
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类型为true时在虚拟机用1代替(boolValue在虚拟机中值为1)

接下来,将第一个 iconst_1 改为 iconst_2( 相当于把boolValue值改为2 )

4.将jasm文件转换为class文件

1
java -jar asmtools.jar jasm Foo.jasm

5.使用 JD-GUI 打开 Foo.class(内容如下)

1
2
3
4
5
6
7
8
9
public class Foo {
public static void main(String[] paramArrayOfString) {
byte b = 2; // 此处修改成功,原本为1
if (b != 0)
System.out.println("Hello, Java!");
if (b == 1)
System.out.println("Hello, JVM!");
}
}

可以看到,我们成功通过修改class文件把boolValue的值改为2了

再次执行:

1
2
3
4
java Foo

# 输出结果
Hello, Java!

可以看到,第二个if条件不成立

三.总结

  1. 学会使用asmtools工具修改class文件:
  • 由 class 文件生成 jasm 文件:java -jar asmtools.jar jdis Foo.class > Foo.jasm
  • 由 jasm 文件生成 class 文件:java -jar asmtools.jar jasm Foo.jasm
  1. 使用JD-GUI可以反编译class文件
  2. 通过上面简单的小例子,证实了boolean类型在虚拟机中值为0或1,有趣的是 if (boolValue) 会被翻译成 if (b != 0)