一个Java字节码解析工具

Overview
   _____ _                 _____                           
  / ____| |               |  __ \                           
 | |    | | __ _ ___ ___  | |__) |_ _ _ __ ___  ___ _ __    
 | |    | |/ _` / __/ __| |  ___/ _` | '__/ __|/ _ \ '__|   
 | |____| | (_| \__ \__ \ | |  | (_| | |  \__ \  __/ |      
  \_____|_|\__,_|___/___/ |_|   \__,_|_|  |___/\___|_|      
                                                                      
                                                                      

Start

一个自己实现的Java字节码文件解析器,目前已经可以解析:

  • 魔数
  • 版本信息
  • 常量池
  • 访问标志
  • 本类、父类信息
  • 接口信息
  • 字段、方法信息
  • 部分属性信息

该解析器会把解析到的信息以json格式的字符串打印出来,修改Main.java.class文件的路径,即可在控制台打印出解析出的信息。

由于属性的结构比较复杂,所以目前可以解析的属性有:

  • Code
  • ConstantValue
  • LineNumberTable
  • LocalVariableTable
  • SourceFile
  • InnerClasses
  • BootstrapMethods
  • Exceptions
  • Synthetic
  • Deprecated
  • Signature
  • MethodParameters

Code 属性中的虚拟机指令(Opcodes)还不能解析,当前会把指令放到一个 byte 数组中,等我学会了虚拟机指令映射再来完善这一功能 😐

Dependence

  • 使用的JDK版本为11
  • Fastjson 1.2.50
  • lombok 1.18.18
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.50</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.18</version>
        </dependency>

TODO

待实现功能:

  • 实现更多属性的解析
  • 解析Code属性中的虚拟机指令

Example

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package class_study;

import java.io.IOException;

public class TestClass implements TestInterface {
    private int id = 3;
    private static final String str = "test";

    public TestClass() {
    }

    public void hello() throws IOException {
        System.out.println("Hello" + this.id);
    }
}

解析结果如下:

{
	"magic":-889275714,
	"minor_version":0,
	"major_version":55,
	"constant_pool_count":62,
	"constant_pool":{
		1:{
			"tag":"CONSTANT_Methodref_info",
			"class_index":"#7 CONSTANT_Class_info",
			"nameAndType_index":"#27 CONSTANT_NameAndType_info"
		},
		2:{
			"tag":"CONSTANT_Fieldref_info",
			"class_index":"#6 CONSTANT_Class_info",
			"nameAndType_index":"#28 CONSTANT_NameAndType_info"
		},
		3:{
			"tag":"CONSTANT_Fieldref_info",
			"class_index":"#29 CONSTANT_Class_info",
			"nameAndType_index":"#30 CONSTANT_NameAndType_info"
		},
		4:{
			"tag":"CONSTANT_Invoke_Dynamic_info",
			"bootstrap_method_attr_index":0,
			"nameAndType_index":"#34 CONSTANT_NameAndType_info"
		},
		5:{
			"tag":"CONSTANT_Methodref_info",
			"class_index":"#35 CONSTANT_Class_info",
			"nameAndType_index":"#36 CONSTANT_NameAndType_info"
		},
		6:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#37 com/company/TestClass"
		},
		7:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#38 java/lang/Object"
		},
		8:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#39 com/company/TestInterface"
		},
		9:{
			"tag":"CONSTANT_Utf8_info",
			"length":2,
			"bytes":"id"
		},
		10:{
			"tag":"CONSTANT_Utf8_info",
			"length":1,
			"bytes":"I"
		},
		11:{
			"tag":"CONSTANT_Utf8_info",
			"length":3,
			"bytes":"str"
		},
		12:{
			"tag":"CONSTANT_Utf8_info",
			"length":18,
			"bytes":"Ljava/lang/String;"
		},
		13:{
			"tag":"CONSTANT_Utf8_info",
			"length":13,
			"bytes":"ConstantValue"
		},
		14:{
			"tag":"CONSTANT_String_info",
			"constant_string_index":"#40 test"
		},
		15:{
			"tag":"CONSTANT_Utf8_info",
			"length":6,
			"bytes":"<init>"
		},
		16:{
			"tag":"CONSTANT_Utf8_info",
			"length":3,
			"bytes":"()V"
		},
		17:{
			"tag":"CONSTANT_Utf8_info",
			"length":4,
			"bytes":"Code"
		},
		18:{
			"tag":"CONSTANT_Utf8_info",
			"length":15,
			"bytes":"LineNumberTable"
		},
		19:{
			"tag":"CONSTANT_Utf8_info",
			"length":18,
			"bytes":"LocalVariableTable"
		},
		20:{
			"tag":"CONSTANT_Utf8_info",
			"length":4,
			"bytes":"this"
		},
		21:{
			"tag":"CONSTANT_Utf8_info",
			"length":23,
			"bytes":"Lcom/company/TestClass;"
		},
		22:{
			"tag":"CONSTANT_Utf8_info",
			"length":5,
			"bytes":"hello"
		},
		23:{
			"tag":"CONSTANT_Utf8_info",
			"length":10,
			"bytes":"Exceptions"
		},
		24:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#41 java/io/IOException"
		},
		25:{
			"tag":"CONSTANT_Utf8_info",
			"length":10,
			"bytes":"SourceFile"
		},
		26:{
			"tag":"CONSTANT_Utf8_info",
			"length":14,
			"bytes":"TestClass.java"
		},
		27:{
			"tag":"CONSTANT_NameAndType_info",
			"constant_name_index":"#15 <init>",
			"constant_type_index":"#16 ()V"
		},
		28:{
			"tag":"CONSTANT_NameAndType_info",
			"constant_name_index":"#9 id",
			"constant_type_index":"#10 I"
		},
		29:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#42 java/lang/System"
		},
		30:{
			"tag":"CONSTANT_NameAndType_info",
			"constant_name_index":"#43 out",
			"constant_type_index":"#44 Ljava/io/PrintStream;"
		},
		31:{
			"tag":"CONSTANT_Utf8_info",
			"length":16,
			"bytes":"BootstrapMethods"
		},
		32:{
			"tag":"CONSTANT_Method_Handle_info",
			"reference_kind":6,
			"reference_index":"#45 CONSTANT_Methodref_info"
		},
		33:{
			"tag":"CONSTANT_String_info",
			"constant_string_index":"#46 Hello\u0001"
		},
		34:{
			"tag":"CONSTANT_NameAndType_info",
			"constant_name_index":"#47 makeConcatWithConstants",
			"constant_type_index":"#48 (I)Ljava/lang/String;"
		},
		35:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#49 java/io/PrintStream"
		},
		36:{
			"tag":"CONSTANT_NameAndType_info",
			"constant_name_index":"#50 println",
			"constant_type_index":"#51 (Ljava/lang/String;)V"
		},
		37:{
			"tag":"CONSTANT_Utf8_info",
			"length":21,
			"bytes":"com/company/TestClass"
		},
		38:{
			"tag":"CONSTANT_Utf8_info",
			"length":16,
			"bytes":"java/lang/Object"
		},
		39:{
			"tag":"CONSTANT_Utf8_info",
			"length":25,
			"bytes":"com/company/TestInterface"
		},
		40:{
			"tag":"CONSTANT_Utf8_info",
			"length":4,
			"bytes":"test"
		},
		41:{
			"tag":"CONSTANT_Utf8_info",
			"length":19,
			"bytes":"java/io/IOException"
		},
		42:{
			"tag":"CONSTANT_Utf8_info",
			"length":16,
			"bytes":"java/lang/System"
		},
		43:{
			"tag":"CONSTANT_Utf8_info",
			"length":3,
			"bytes":"out"
		},
		44:{
			"tag":"CONSTANT_Utf8_info",
			"length":21,
			"bytes":"Ljava/io/PrintStream;"
		},
		45:{
			"tag":"CONSTANT_Methodref_info",
			"class_index":"#52 CONSTANT_Class_info",
			"nameAndType_index":"#53 CONSTANT_NameAndType_info"
		},
		46:{
			"tag":"CONSTANT_Utf8_info",
			"length":6,
			"bytes":"Hello\u0001"
		},
		47:{
			"tag":"CONSTANT_Utf8_info",
			"length":23,
			"bytes":"makeConcatWithConstants"
		},
		48:{
			"tag":"CONSTANT_Utf8_info",
			"length":21,
			"bytes":"(I)Ljava/lang/String;"
		},
		49:{
			"tag":"CONSTANT_Utf8_info",
			"length":19,
			"bytes":"java/io/PrintStream"
		},
		50:{
			"tag":"CONSTANT_Utf8_info",
			"length":7,
			"bytes":"println"
		},
		51:{
			"tag":"CONSTANT_Utf8_info",
			"length":21,
			"bytes":"(Ljava/lang/String;)V"
		},
		52:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#54 java/lang/invoke/StringConcatFactory"
		},
		53:{
			"tag":"CONSTANT_NameAndType_info",
			"constant_name_index":"#47 makeConcatWithConstants",
			"constant_type_index":"#58 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"
		},
		54:{
			"tag":"CONSTANT_Utf8_info",
			"length":36,
			"bytes":"java/lang/invoke/StringConcatFactory"
		},
		55:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#60 java/lang/invoke/MethodHandles$Lookup"
		},
		56:{
			"tag":"CONSTANT_Utf8_info",
			"length":6,
			"bytes":"Lookup"
		},
		57:{
			"tag":"CONSTANT_Utf8_info",
			"length":12,
			"bytes":"InnerClasses"
		},
		58:{
			"tag":"CONSTANT_Utf8_info",
			"length":152,
			"bytes":"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"
		},
		59:{
			"tag":"CONSTANT_Class_info",
			"constant_class_index":"#61 java/lang/invoke/MethodHandles"
		},
		60:{
			"tag":"CONSTANT_Utf8_info",
			"length":37,
			"bytes":"java/lang/invoke/MethodHandles$Lookup"
		},
		61:{
			"tag":"CONSTANT_Utf8_info",
			"length":30,
			"bytes":"java/lang/invoke/MethodHandles"
		}
	},
	"access_flags":33,
	"this_class":"#6  com/company/TestClass",
	"super_class":"#7  java/lang/Object",
	"interfaces_count":1,
	"interfaces_info_array":[
		"#8  com/company/TestInterface"
	],
	"fields_count":2,
	"fields":{
		"field #0":{
			"access_flags":2,
			"name_index":"#9 id",
			"descriptor_index":"#10 I",
			"attributes_count":0,
			"attribute_info":{
				
			}
		},
		"field #1":{
			"access_flags":26,
			"name_index":"#11 str",
			"descriptor_index":"#12 Ljava/lang/String;",
			"attributes_count":1,
			"attribute_info":{
				"attribute #0":{
					"attribute_name_index":"#13 ConstantValue",
					"attribute_length":2,
					"constant_value_index":"#14  test"
				}
			}
		}
	},
	"methods_count":2,
	"methods":{
		"method #0":{
			"access_flags":1,
			"name_index":"#15 <init>",
			"descriptor_index":"#16 ()V",
			"attributes_count":1,
			"attribute_info":{
				"attribute #0":{
					"attribute_name_index":"#17 Code",
					"attribute_length":60,
					"max_stack":2,
					"max_locals":1,
					"code_length":10,
					"code":"KrcAASoGtQACsQ==",
					"exception_table_length":0,
					"attributes_count":2,
					"Code_attribute_info":{
						"attribute #0":{
							"attribute_name_index":"#18 LineNumberTable",
							"attribute_length":14,
							"line_number_table_length":3,
							"line_number_table #0":{
								"start_pc":0,
								"line_number":13
							},
							"line_number_table #1":{
								"start_pc":4,
								"line_number":14
							},
							"line_number_table #2":{
								"start_pc":9,
								"line_number":15
							}
						},
						"attribute #1":{
							"attribute_name_index":"#19 LocalVariableTable",
							"attribute_length":12,
							"local_variable_table_length":1,
							"local_variable_table #0":{
								"start_pc":0,
								"length":10,
								"name_index":"#20 this",
								"descriptor_index":"#21 Lcom/company/TestClass;",
								"index":0
							}
						}
					}
				}
			}
		},
		"method #1":{
			"access_flags":1,
			"name_index":"#22 hello",
			"descriptor_index":"#16 ()V",
			"attributes_count":2,
			"attribute_info":{
				"attribute #0":{
					"attribute_name_index":"#17 Code",
					"attribute_length":62,
					"max_stack":2,
					"max_locals":1,
					"code_length":16,
					"code":"sgADKrQAAroABAAAtgAFsQ==",
					"exception_table_length":0,
					"attributes_count":2,
					"Code_attribute_info":{
						"attribute #0":{
							"attribute_name_index":"#18 LineNumberTable",
							"attribute_length":10,
							"line_number_table_length":2,
							"line_number_table #0":{
								"start_pc":0,
								"line_number":19
							},
							"line_number_table #1":{
								"start_pc":15,
								"line_number":20
							}
						},
						"attribute #1":{
							"attribute_name_index":"#19 LocalVariableTable",
							"attribute_length":12,
							"local_variable_table_length":1,
							"local_variable_table #0":{
								"start_pc":0,
								"length":16,
								"name_index":"#20 this",
								"descriptor_index":"#21 Lcom/company/TestClass;",
								"index":0
							}
						}
					}
				},
				"attribute #1":{
					"attribute_name_index":"#23 Exceptions",
					"attribute_length":4,
					"number_of_exceptions":1,
					"exception_index_table":[
						"#24  java/io/IOException"
					]
				}
			}
		}
	},
	"attribute_count":3,
	"attributes":{
		"attribute #0":{
			"attribute_name_index":"#25 SourceFile",
			"attribute_length":2,
			"source_file_index":"#26 TestClass.java"
		},
		"attribute #1":{
			"attribute_name_index":"#57 InnerClasses",
			"attribute_length":10,
			"number_of_classes":1,
			"classes #0":{
				"inner_class_info_index":"#55  java/lang/invoke/MethodHandles$Lookup",
				"outer_class_info_index":"#59  java/lang/invoke/MethodHandles",
				"inner_name_index":"#56 Lookup",
				"inner_class_access":25
			}
		},
		"attribute #2":{
			"attribute_name_index":"#31 BootstrapMethods",
			"attribute_length":8,
			"num_bootstrap_methods":1,
			"bootstrap_methods #0":{
				"bootstrap_method_ref":"#32  CONSTANT_Methodref_info",
				"num_bootstrap_arguments":1,
				"bootstrap_arguments":[
					"#33  Hello\u0001"
				]
			}
		}
	}
}

Log

  • version 1.1:
    • 增加了可解析的属性
    • 优化索引算法
    • 修复了一些bug
  • version 1.0:
    • 实现字节码文件基本信息解析

Refer

  • FormatUtil类来自于作者 lizhgb 开源的json字符串格式化的代码
You might also like...
Owner
F4DE
Web Security | Student
F4DE