当前位置: 移动技术网 > IT编程>开发语言>Java > Java关于字节码文件的解析

Java关于字节码文件的解析

2020年08月17日  | 移动技术网IT编程  | 我要评论
字节码文件解析最近有回过头看了一下jvm并且去看了一下他的一部分c语言的源码。打算尝试用Java写一个分析字节码文件的小程序。这里写了一个class来手动分析一下字节码的解析过程public class jvmclasstest { public int i = 1; public static Integer a = 2; private String s = "caohao"; public static void main(String[] args) {

字节码文件解析

最近有回过头看了一下jvm并且去看了一下他的一部分c语言的源码。打算尝试用Java写一个分析字节码文件的小程序。
这里写了一个class来手动分析一下字节码的解析过程

public class jvmclasstest { public int i = 1; public static Integer a = 2; private String s = "caohao"; public static void main(String[] args) { jvmclasstest test = new jvmclasstest(); test.test(10); } public void test(int a){ this.i = a; } } 

这里选用了一个叫做Synalyze It! Pro的16进制查看工具

一个字节码文件大概是由以下几个部分构成

  1. 魔数
  2. 版本号
  3. 常量池
  4. 这个类的access_flag
  5. this_class
  6. super_class
  7. interfaces
  8. fileds
  9. methods
  10. attributes

字节码文件的内容如下:

HEX DUMP: [00000010] CA FE BA BE 00 00 00 34 00 2E 0A 00 0A 00 21 09 .......4 ........ [00000020] 00 05 00 22 08 00 23 09 00 05 00 24 07 00 25 0A ........ ........ [00000030] 00 05 00 21 0A 00 05 00 26 0A 00 27 00 28 09 00 ........ ........ [00000040] 05 00 29 07 00 2A 01 00 01 69 01 00 01 49 01 00 ........ .i...I.. [00000050] 01 61 01 00 13 4C 6A 61 76 61 2F 6C 61 6E 67 2F .a...Lja va.lang. [00000060] 49 6E 74 65 67 65 72 3B 01 00 01 73 01 00 12 4C   Integer. ...s...L [00000070] 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 java.lan g.String [00000080] 3B 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 56 .....ini t......V [00000090] 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E 75 ...Code. ..LineNu [000000a0] 6D 62 65 72 54 61 62 6C 65 01 00 12 4C 6F 63 61 mberTabl e...Loca [000000b0] 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 01 00 lVariabl eTable.. [000000c0] 04 74 68 69 73 01 00 0E 4C 6A 76 6D 63 6C 61 73 .this... Ljvmclas [000000d0] 73 74 65 73 74 3B 01 00 04 6D 61 69 6E 01 00 16 stest... .main... [000000e0] 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 ..Ljava. lang.Str [000000f0] 69 6E 67 3B 29 56 01 00 04 61 72 67 73 01 00 13 ing..V.. .args... [00000100] 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 .Ljava.l ang.Stri [00000110] 6E 67 3B 01 00 04 74 65 73 74 01 00 04 28 49 29 ng....te st....I. [00000120] 56 01 00 08 3C 63 6C 69 6E 69 74 3E 01 00 0A 53 V....cli nit....S [00000130] 6F 75 72 63 65 46 69 6C 65 01 00 11 6A 76 6D 63 ourceFil e...jvmc [00000140] 6C 61 73 73 74 65 73 74 2E 6A 61 76 61 0C 00 11 lasstest .java... [00000150] 00 12 0C 00 0B 00 0C 01 00 06 63 61 6F 68 61 6F ........ ..caohao [00000160] 0C 00 0F 00 10 01 00 0C 6A 76 6D 63 6C 61 73 73 ........ jvmclass [00000170] 74 65 73 74 0C 00 1C 00 1D 07 00 2B 0C 00 2C 00 test.... ........ [00000180] 2D 0C 00 0D 00 0E 01 00 10 6A 61 76 61 2F 6C 61 ........ .java.la [00000190] 6E 67 2F 4F 62 6A 65 63 74 01 00 11 6A 61 76 61 ng.Objec t...java [000001a0] 2F 6C 61 6E 67 2F 49 6E 74 65 67 65 72 01 00 07 .lang.In teger... [000001b0] 76 61 6C 75 65 4F 66 01 00 16 28 49 29 4C 6A 61 valueOf. ...I.Lja [000001c0] 76 61 2F 6C 61 6E 67 2F 49 6E 74 65 67 65 72 3B   va.lang. Integer. [000001d0] 00 21 00 05 00 0A 00 00 00 03 00 01 00 0B 00 0C ........ ........ [000001e0] 00 00 00 09 00 0D 00 0E 00 00 00 02 00 0F 00 10 ........ ........ [000001f0] 00 00 00 04 00 01 00 11 00 12 00 01 00 13 00 00 ........ ........ [00000200] 00 42 00 02 00 01 00 00 00 10 2A B7 00 01 2A 04 .B...... ........ [00000210] B5 00 02 2A 12 03 B5 00 04 B1 00 00 00 02 00 14 ........ ........ [00000220] 00 00 00 0E 00 03 00 00 00 01 00 04 00 02 00 09 ........ ........ [00000230] 00 04 00 15 00 00 00 0C 00 01 00 00 00 10 00 16 ........ ........ [00000240] 00 17 00 00 00 09 00 18 00 19 00 01 00 13 00 00 ........ ........ [00000250] 00 4B 00 02 00 02 00 00 00 0F BB 00 05 59 B7 00 .K...... .....Y.. [00000260] 06 4C 2B 10 0A B6 00 07 B1 00 00 00 02 00 14 00 .L...... ........ [00000270] 00 00 0E 00 03 00 00 00 07 00 08 00 08 00 0E 00 ........ ........ [00000280] 09 00 15 00 00 00 16 00 02 00 00 00 0F 00 1A 00 ........ ........ [00000290] 1B 00 00 00 08 00 07 00 1C 00 17 00 01 00 01 00 ........ ........ [000002a0] 1C 00 1D 00 01 00 13 00 00 00 3E 00 02 00 02 00 ........ ........ [000002b0] 00 00 06 2A 1B B5 00 02 B1 00 00 00 02 00 14 00 ........ ........ [000002c0] 00 00 0A 00 02 00 00 00 0C 00 05 00 0D 00 15 00 ........ ........ [000002d0] 00 00 16 00 02 00 00 00 06 00 16 00 17 00 00 00 ........ ........ [000002e0] 00 00 06 00 0D 00 0C 00 01 00 08 00 1E 00 12 00 ........ ........ [000002f0] 01 00 13 00 00 00 20 00 01 00 00 00 00 00 08 05 ........ ........ [00000300] B8 00 08 B3 00 09 B1 00 00 00 01 00 14 00 00 00 ........ ........ [00000310] 06 00 01 00 00 00 03 00 01 00 1F 00 00 00 02 00 ........ ........ [00000310] 20 . 

下面来依次分析内容

魔数与版本号

第一个看到的就是传说中的cafebaby他占据了开始的四个字节并且内容一定是0xCAFEBABY
接下来就是主版本号和次版本号了,JVM的版本是向下兼容的也就是说如果当前我们的JDK是1.8的话运行起来的JVM进程会兼容1.7版本JDK所写的字节码文件而这里的检查就是看魔数后面的这两个版本号来检查的
版本号依旧占据了四个字节前两个是主版本号后两个字节是次版本号,咱们这里是00 00 00 34对应的数字就是52也就是JDK1.8 Java的版本号是从45开始计算作为JDK1.1随后依次加1,比如说JDK1.2就是46这样的

常量池

接下来就是重中之重常量池了,其实JVM内部使用C的一系列oop-klass模型的实例对象来储存这些信息,不过这里不做介绍就简单的来分析一下常量池的这部分字节码
首先一定是一个常量池中的常量个数随后跟着一系列的常量元素的信息而每一个元素都是由一个tag和一个date组成
tag作为标签标定了当前元素是那种类型的常量,JVM定义了11中常量如下

这里的tag占据了一个字节

名称 tag标记 含义
1 CONSTANT_utf8_Info utf8编码的字符串
3 CONSTANT_Integer_Info 整形字面量
4 CONSTANT_Float_Info 浮点型
5 CONSTANT_Long_Info 长整型
6 CONSTANT_Double_Info 双精度型
7 CONSTANT_Class_Info 类或者接口的引用
8 CONSTANT_String_Info 字符串类型
9 CONSTANT_Fieldref_Info 字段的引用
10 CONSTANT_Methodref_Info 方法的引用
11 CONSTANT_InterfaceMrthodref_Info 接口中方法的引用
12 CONSTANT_NameAndType_Info 字段和方法名称以及类型的符号引用

上面的11种元素类型都在JVM内部以某种C类的结构来储存信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1O8fnB8g-1597565623257)(img/JVM常量池复合元素.png)]

除了utf8以外的结构都没有length这个属性,其他的都是tag+index而这个是tag+byte+length

length的含义就是表示bytes的长度而bytes则是他的内容数据所以说他的长度是1+2+length

而其他的都是1+2或者1+2+2

在JVM内用U2来描述contentpool的元素个数也就是两个字节,我们这里他是0x00 2E也就是46个元素JVM规定0这个位置不能使用可能是为了方便吧。

这里不会全部解析拿出一两个看一下就行

第一个元素

根据上面的分析首先会是一个占据一个字节大小的tag 0X0A这里的tag是10也就是CONSTANT_Methodref_Info

他的结构是 tag index index这样的结构

随后就是两个U2的索引分别是00 0A和 00 21也就是10和33分别代表了常量池中的第十个和第33个常量

第二个元素

随后就是第二个元素了首先tag是09代表了CONSTANT_Fieldref_Info字段信息

他的结构是tag加两个索引所以还是往后读两个U2是00 05和 00 22

其他的也都是这样的元素

访问标记和继承信息

接下来就是access_flag,this_class,super_class和interface了

首先就是U2的access_flag

他也是在JVM内部规定好了的格式

名称 标记 含义
ACC_PUBLIC 0x0001 是否为public
ACC_FINAL 0x0010 是否被声明了final
ACC_SUPER 0x0020 是否允许invokespecial,JDK1.2后编译出来的类这个都为真
ACC_INTERFACE 0x0200 标记是一个接口
ACC_ABSTRACT 0x0400 标记抽象类或者接口
ACC_SYNTHETIC 0x1000 标记这个类并非是用户代码所产生的
ACC_ANNOTATION 0x2000 标记是一个注解
ACC_ENUM 0x4000 一个枚举

我们这里这一项是0x00 21也就是super+public是一个public修饰的class

然后是this_class标记,是一个U2的索引指向常量池中˙的一个元素,我们这里是0x00 05也就是常量池中的第5个元素这个元素是一个classinfo他的index是37在去看37元素是一个Utf8他的bytes是jvmclasstest也就是我们的类名

随后就是superclass了这个和thisclass基本一致的解析也是一个index,我们这里是0x00 0A也就是索引10这里的10是一个classinfo他的index是42我们的42是utf8他的bytes是java/lang/Object

在后面就是我们的interface了我们的类是可以实现很多接口的所以,不出意外和constantpool一样会先有一个interface的count这个byte之后就是一系列的interface了这里的count也是一个u2的数据我们这里是0x00 00因为我们并没有实现接口所以是这样的不过就算有后面的也都是一些指向常量池的u2索引而已。

字段信息

接下来就是我们的field了。其实上面分析了这么多应该有经验了像是这种多个元素的都会是数量+元素数组的形式存在。

那么首先就是一个u2的count,我们这里是0x00 03也就是三个field,和我们的类是完全一致的。

随后就是一系列的field_info了这个fieldinfo也是JVM内部定义的一种结构它由以下几种内容组成

  1. u2的accessflag这个内容有一个
  2. u2的fieldname的索引指向constantpool
  3. u2的描述信息也是一个index
  4. u2的field的attribute数量
  5. 一系列的attribute_info

这就是field的结构,下面来分析一下我们的例子类

我们拿出个field来看,我们在类里定义的第一个field是 public int i = 1;

首先是accessflag:00 01是一个public

fieldname:00 0B index11->utf8的i

描述:00 0C。index12是一个utf8的大写的I代表了int

count:00 00也就是没有内部attribute

方法信息

method和field的内容基本上是一样的首先也是一个u2的count

随后就是一系列的method_info了甚至methodinfo的结构和fieldinfo也是一样的感兴趣的可以自己分析一下这个16进制文件

本文地址:https://blog.csdn.net/qq_43147121/article/details/108035464

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网