盘古BPM体验地址    盘古BPM交流群盘古BPM交流群号:963222735

自己读class文件实战

分享牛 2140℃

    在讲解如何阅读class文件之前,我们需要看一下classFile的格式,要不然貌似直接看十六进制的就晕菜了,思路如下:

1.定义一个简单的类。

2.使用javap -verbose 看下编译之后的字节码。可以参考文章 java class结构以及javap命令的使用

3.使用文本编辑器打开class字节码,注意打开字节码阅读的时候,一定要使用16进制的方式打开,可以使用ueditor或者notepad++工具进行字节码的查看。

接下来就开始讲解如何阅读。

1.定义一个类,类的详细定义如下所示:

public class Hello {
private static String msg = "分享牛";
public static void main(String[] args) {
System.out.println("msg=="+msg);
}
}

说明:Hello类中定义了一个静态字段msg。以及一个方法main,并且在main方法中打印msg的信息。

2.使用ueditor打开Hello.class ,注意这里打开的是字节码,并非是java源文件。正常情况下打开之后,切换到16进制,如下图所示:

3.详细说明一下ClassFile结构以及阅读技巧。

ClassFile结构如下图所示:

u4就表示是4个字节,同理u2表示2个字节。cp_info我们可以称之为表,这个查找方法稍微不太一样。

3.1魔数的查找

前四个字节表示魔数,通常固定的值是CAFEBABE,该值的唯一作用就是字节码文件是否可以被jvm所接受。

3.2 版本号的查找

版本号有主版本号+副版本号。

3.3. 常量池计数器 

常量池计数器的值等于常量池的数量+1

接下来,我们看一下上述的三个字节码如何查看。截图如下:

注意这里是16进制,所以最终的版本号为:52(jdk8版本)。

常量池计数器:53,所以最终的常量应该是52个,那我们看一下javap -verbose 看下编译之后的字节码详细信息。最后一个常量信息如下:

#52 = Utf8               Hello.java

那也证明,我们看对了,确实如此。

3.4  常量查找

变量的查找比较复杂。因为常量的类型是表:由多个无符号数和其它表构成的复合数据类型,通常以”_info”结尾

我们看一下cp_info的格式,如下图所示:

第一位是变量的类型,说白了这个变量是字符串、类、long等等。、

第二位是变量的值。 info[]值有info决定的。根据类型找结构。

注意:先找tag,查找完毕之后,开始查找info[]

3.4.1 开始查找变量,同样以下图为例继续展开说明:

首先查找07变量是什么类型,如下图所示。

07是一个类,那我们查找到该类的_info定义,如下图所示:

 u1就是tag,不用管。

 u2 那就继续找两个,代表了变量在变量池的索引 如下图所示:

02的变量为: #2 = Utf8               com/shareniu/helloword/Hello

果真是Hello类,并且是全限定名称。

那我们继续查找info[]信息。跟上面的方法一样。

我们找到了01类型的变量(CONSTANT_Utf8_info),对应的结构如下所示:

u2是长度,变量的值为byte[length]。首先看一下我们最终查询的结果图如下所示:

00 1c 对应的十进制应该是28,那换言之向后查找28个字节就是该变量的值了,1C向后查找28个字节刚好到了6F,其中 63-6F对应的值为:  com/shareniu/helloword/Hello,大家可以在ueditor中选中这几个字节查看验证下。至此第一个变量以及对应的值,我们已经成功找到了。接下来还是上述的方法,查找下一个,那我们继续查找第二个 从07开始。步骤如下:

1.07 向后查找2个对应 00 04 所以变量的索引是4对应:

#4 = Utf8               java/lang/Object

2.01是CONSTANT_Utf8_info,所以00 10 是变量的长度,十进制应该是16,具体覆盖的字节数目如下所示:

6A-74对应的变量值刚好是java/lang/Object

剩下的就是依次类推进行查找了,在这里就不一一说明了。如果不明白的,可以文章下面留言交流。


转载请注明:分享牛 » 自己读class文件实战