Skip to content

使用java实现一个class字节码解析工具

Notifications You must be signed in to change notification settings

JuneLeo/class-parse

Repository files navigation

class-parse

Parse

parse

每个颜色代表一种解析器

code table

parse

Constant Pool

类型 字段 描述
CONSTANT_Utf8_info tag/length/bytes(u1) UTF-8字符串
CONSTANT_Integer_info tag/bytes(u4) int
CONSTANT_Float_info tag/bytes(u4) float
CONSTANT_Long_info tag/bytes(u8) long
CONSTANT_Double_info tag/bytes(u8) double
CONSTANT_Class_info tag/index 类或者接口符号引用
CONSTANT_String_info tag/index 字符串类型字面量
CONSTANT_Fieldref_info tag/index类/index 字段符号引用
CONSTANT_Methodref_info tag/index类/index 类中方法符号引用
CONSTANT_Interface-Methodref_info tag/index接口类/index 接口中方法符号引用
CONSTANT_NameAndType_info tag/index名称/index签名 字段或者方法的部分符号引用
CONSTANT_Method-Handle_info 方法句柄
CONSTANT_Method-type_info 标识方法类型
CONSTANT_Invoke-Dynamic_info 动态方法调用点

Attribute

类型 描述
Code 方法表
LineNumberTable 调试表
LocalVariableTable 本地变量表
SourceFile 源文件表
Exceptions 异常表
ConstantValue 异常表
InnerClasses 内部类表
Deprecated 废弃标识
Synthetic 表示方法或者字段
StackMapTable 类型检查器
Signature 泛型的方法签名 - 泛型会类型擦除
BootstrapMethods invokedymic相关
LocalVariableTypeTable 泛型相关
还有很多其他未解析的表

Example

  • Person
public class Person {
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void play(String name) {
        if (name.equals("basket")) {
            System.out.println("篮球");
        }

    }
}
  • Person 解析
magic: CAFEBABE
minor: 0
major: 52
Constant pool: 
    #1 = [ name=CONSTANT_Methodref_info, classIndex=10, nameAndTypeIndex=27 ]
    #2 = [ name=CONSTANT_Fieldref_info, classIndex=9, nameAndTypeIndex=28 ]
    #3 = [ name=CONSTANT_Fieldref_info, classIndex=9, nameAndTypeIndex=29 ]
    #4 = [ name=CONSTANT_String_info, index=30 ]
    #5 = [ name=CONSTANT_Methodref_info, classIndex=31, nameAndTypeIndex=32 ]
    #6 = [ name=CONSTANT_Fieldref_info, classIndex=33, nameAndTypeIndex=34 ]
    #7 = [ name=CONSTANT_String_info, index=35 ]
    #8 = [ name=CONSTANT_Methodref_info, classIndex=36, nameAndTypeIndex=37 ]
    #9 = [ name=CONSTANT_Class_info, index=38 ]
    #10 = [ name=CONSTANT_Class_info, index=39 ]
    #11 = [ name=CONSTANT_Utf8_info, length=4, value='name ]
    #12 = [ name=CONSTANT_Utf8_info, length=18, value='Ljava/lang/String; ]
    #13 = [ name=CONSTANT_Utf8_info, length=3, value='age ]
    #14 = [ name=CONSTANT_Utf8_info, length=1, value='I ]
    #15 = [ name=CONSTANT_Utf8_info, length=6, value='<init> ]
    #16 = [ name=CONSTANT_Utf8_info, length=22, value='(Ljava/lang/String;I)V ]
    #17 = [ name=CONSTANT_Utf8_info, length=4, value='Code ]
    #18 = [ name=CONSTANT_Utf8_info, length=15, value='LineNumberTable ]
    #19 = [ name=CONSTANT_Utf8_info, length=18, value='LocalVariableTable ]
    #20 = [ name=CONSTANT_Utf8_info, length=4, value='this ]
    #21 = [ name=CONSTANT_Utf8_info, length=20, value='Lorg/example/Person; ]
    #22 = [ name=CONSTANT_Utf8_info, length=4, value='play ]
    #23 = [ name=CONSTANT_Utf8_info, length=21, value='(Ljava/lang/String;)V ]
    #24 = [ name=CONSTANT_Utf8_info, length=13, value='StackMapTable ]
    #25 = [ name=CONSTANT_Utf8_info, length=10, value='SourceFile ]
    #26 = [ name=CONSTANT_Utf8_info, length=11, value='Person.java ]
    #27 = [ name=CONSTANT_NameAndType_info, nameIndex=15, signatureIndex=40 ]
    #28 = [ name=CONSTANT_NameAndType_info, nameIndex=11, signatureIndex=12 ]
    #29 = [ name=CONSTANT_NameAndType_info, nameIndex=13, signatureIndex=14 ]
    #30 = [ name=CONSTANT_Utf8_info, length=6, value='basket ]
    #31 = [ name=CONSTANT_Class_info, index=41 ]
    #32 = [ name=CONSTANT_NameAndType_info, nameIndex=42, signatureIndex=43 ]
    #33 = [ name=CONSTANT_Class_info, index=44 ]
    #34 = [ name=CONSTANT_NameAndType_info, nameIndex=45, signatureIndex=46 ]
    #35 = [ name=CONSTANT_Utf8_info, length=6, value='篮球 ]
    #36 = [ name=CONSTANT_Class_info, index=47 ]
    #37 = [ name=CONSTANT_NameAndType_info, nameIndex=48, signatureIndex=23 ]
    #38 = [ name=CONSTANT_Utf8_info, length=18, value='org/example/Person ]
    #39 = [ name=CONSTANT_Utf8_info, length=16, value='java/lang/Object ]
    #40 = [ name=CONSTANT_Utf8_info, length=3, value='()V ]
    #41 = [ name=CONSTANT_Utf8_info, length=16, value='java/lang/String ]
    #42 = [ name=CONSTANT_Utf8_info, length=6, value='equals ]
    #43 = [ name=CONSTANT_Utf8_info, length=21, value='(Ljava/lang/Object;)Z ]
    #44 = [ name=CONSTANT_Utf8_info, length=16, value='java/lang/System ]
    #45 = [ name=CONSTANT_Utf8_info, length=3, value='out ]
    #46 = [ name=CONSTANT_Utf8_info, length=21, value='Ljava/io/PrintStream; ]
    #47 = [ name=CONSTANT_Utf8_info, length=19, value='java/io/PrintStream ]
    #48 = [ name=CONSTANT_Utf8_info, length=7, value='println ]
flags: ACC_PUBLIC,ACC_SUPER
---------------------------------------
flags: ACC_PUBLIC
filed: name
descriptor: Ljava/lang/String;
---------------------------------------
flags: ACC_PUBLIC
filed: age
descriptor: I
---------------------------------------
flags: ACC_PUBLIC
method: <init>
descriptor: (Ljava/lang/String;I)V
Code:
    maxStack=2  maxLocals=3
        0: aload_0
        1: invokespecial java/lang/Object  <init>  ()V
        4: aload_0
        5: aload_1
        6: putfield org/example/Person  name  Ljava/lang/String;
        9: aload_0
        10: iload_2
        11: putfield org/example/Person  age  I
        14: return
LineNumberTable:
    line 8:0
    line 9:4
    line 10:9
    line 11:14
LocalVariableTable:
    Start=0, Length=15, Slot=0, nameIndex=this, descriptorIndex=Lorg/example/Person;
    Start=0, Length=15, Slot=1, nameIndex=name, descriptorIndex=Ljava/lang/String;
    Start=0, Length=15, Slot=2, nameIndex=age, descriptorIndex=I
---------------------------------------
flags: ACC_PUBLIC
method: play
descriptor: (Ljava/lang/String;)V
Code:
    maxStack=2  maxLocals=2
        0: aload_1
        1: ldc basket
        3: invokevirtual java/lang/String  equals  (Ljava/lang/Object;)Z
        6: ifeq name
        9: getstatic java/lang/System  out  Ljava/io/PrintStream;
        12: ldc 篮球
        14: invokevirtual java/io/PrintStream  println  (Ljava/lang/String;)V
        17: return
LineNumberTable:
    line 15:0
    line 16:9
    line 18:17
LocalVariableTable:
    Start=0, Length=18, Slot=0, nameIndex=this, descriptorIndex=Lorg/example/Person;
    Start=0, Length=18, Slot=1, nameIndex=name, descriptorIndex=Ljava/lang/String;
StackMapTable:
    frame_type=17
---------------------------------------
SourceFile: 
    Person.java

解析接口

public interface Parse {
    int parse(int start, byte[] code);
}
  • code:为class字节码
  • start:解析器开始解析位置
  • return:下一个解析器开始解析的位置

ClassFormat

public class ClassFormat {
    
    private List<Parse> parses = new ArrayList<>();
    
    public ClassFormat() {
        parses.add(new MagicParse()); //magic解析器
        parses.add(new VersionParse()); // 版本解析器
        parses.add(new ConstantParse()); // 常量池解析器
        parses.add(new AccessFlagParse()); // class access flag解析器
        parses.add(new ClassExtParse());  // class info解析器
        parses.add(new InterfaceParse()); // class的接口解析器
        parses.add(new FieldParse()); // field变量解析器
        parses.add(new MethodParse());   // method方法解析器
        parses.add(new AttributeParse());  // 类的其他属性解析器
    }


    public void parse(byte[] bytes) {
        int start = 0;
        for (Parse pars : parses) {
            start = pars.parse(start, bytes);
        }
    }
}

About

使用java实现一个class字节码解析工具

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages