日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

.class文件格式(java字节码文件的格式)

發布時間:2024/4/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .class文件格式(java字节码文件的格式) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一個.class文件對應一個類(Class)


包含字節碼(虛擬機指令)?



1 目的

Java 虛擬機識別的 class 文件格式包含 Java 虛擬機指令 (或者 bytecodes )和一個符號表以及其他的輔助信息。本文將使用 VC++ 語言解析 Java Class 文件符號表,逆向生成 Java 源代碼結構。如圖 1

?

????????????????????????????????????????????????????????????????????????????????????????? 圖1

之所以使用 VC++ 而不使用 Java 的主要是因為 VC++ 界面開發簡單;運行速度快,不需要虛擬機;需要用指針建立復雜的數據結構。

2 實現

實現該工具的過程如下:

1. 解析 Class 文件,從 Class 文件中讀取數據并保存到稱為 ClassFile 結構體中;

2. 解析 ClassFile 結構體,生成源代碼字符串;

3. 將字符串顯示到視圖中。

2.1 解析 Class 文件

為實現第 1 步,首先需要了解 Class 文件格式規范,參考《 Java 虛擬機規范》第四章 class 文件格式,總結 class 文件的數據結構如圖 2

2.1.1 Class 文件格式

Class 文件格式 ClassFile 結構體的 C 語言描述如下:

struct ClassFile

{

????????????? u4 magic;?????????????????????????? ????? // 識別 Class 文件格式,具體值為 0xCAFEBABE

????????????? u2 minor_version;??????????? // Class 文件格式副版本號,

????????????? u2 major_version;??????????? // Class 文件格式主版本號,

????????????? u2 constant_pool_count; //? 常數表項個數,

????????????? cp_info **constant_pool;// 常數表,又稱變長符號表,

????????????? u2 access_flags;????????????? ? //Class 的聲明中使用的修飾符掩碼,

????????????? u2 this_class;?????????????????? // 常數表索引,索引內保存類名或接口名,

????????????? u2 super_class;??????????????? // 常數表索引,索引內保存父類名,

????????????? u2 interfaces_count;??????? // 超接口個數,

????????????? u2 *interfaces;???????????????? // 常數表索引,各超接口名稱,

????????????? u2 fields_count;? ???? // 類的域個數,

????????????? field_info **fields;????????? // 域數據,包括屬性名稱索引,

// 域修飾符掩碼等,

????????????? u2 methods_count;???????? ? // 方法個數,

????????????? method_info **methods;// 方法數據,包括方法名稱索引,方法修飾符掩碼等,

????????????? u2 attributes_count;?????? ? // 類附加屬性個數,

????????????? attribute_info **attributes; // 類附加屬性數據,包括源文件名等。

};

?

其中 u2 unsigned short u4 unsigned long

typedef unsigned char? ? u1;

typedef unsigned short ? u2;

typedef unsigned long ?? u4;

?

cp_info **constant_pool 是常量表的指針數組,指針數組個數為 constant_pool_count ,結構體 cp_info

struct cp_info

{

????????????? u1 tag;?????? // 常數表數據類型

????????????? u1 *info;?? // 常數表數據

};

常數表數據類型 Tag 定義如下:

#define CONSTANT_Class??????????????? ????????????????????????? 7?????

#define CONSTANT_Fieldref???????????? ???????????????????????? 9

#define CONSTANT_Methodref????????????????????????????? ? 10

#define CONSTANT_InterfaceMethodref?? ??????????????? 11

#define CONSTANT_String??????????????????????????????????????????????????? ? 8

#define CONSTANT_Integer??????????????????????????????????? ? ???????????? 3

#define CONSTANT_Float???????????????????????????????????????????????????? ? 4

#define CONSTANT_Long???????????????????????? ??????????????????????????? ? 5

#define CONSTANT_Double????????????? ???????????????????????? 6

#define CONSTANT_NameAndType????????? ??????????????? 12

#define CONSTANT_Utf8????????????????????????????????????????????????????? ? 1

每種類型對應一個結構體保存該類型數據,例如 CONSTANT_Class info 指針指向的數據類型應為 CONSTANT_Class_info

struct CONSTANT_Class_info

{

????????????? u1 tag;

????????????? u2 name_index;

};

2

CONSTANT_Utf8 info 指針指向的數據類型應為 CONSTANT_Utf8_info

struct CONSTANT_Utf8_info

{

????????????? u1 tag;

????????????? u2 length;

????????????? u1 *bytes;

};

Tag info 的詳細說明參考《 Java 虛擬機規范》第四章 4.4 節。

access_flags 為類修飾符掩碼,域與方法都有各自的修飾符掩碼。

#define ACC_PUBLIC??????????????????????????????? 0x0001?

#define ACC_PRIVATE???????????????????????????? 0x0002

#define ACC_PROTECTED?????????????????????? ??????????? 0x0004

#define ACC_STATIC??????????????????????????????? 0x0008

#define ACC_FINAL????????????????????????????????? ??????????? 0x0010

#define ACC_SYNCHRONIZED????????????? ??????????? 0x0020

#define ACC_SUPER????????????????????????????????? ????????????? 0x0020

#define ACC_VOLATILE????????????????????????? ????????????? 0x0040

#define ACC_TRANSIENT??????????????????????? ????????????? 0x0080?

#define ACC_NATIVE?????????????????????????????? 0x0100

#define ACC_INTERFACE??????????????????????? ????????????? 0x0200?

#define ACC_ABSTRACT???????????????????????? ????????????? 0x0400?

#define ACC_STRICT???????? ???????????????????????????? 0x0800

例如類的修飾符為 public abstract access_flags 的值為 ACC_PUBLIC | ACC_ABSTRACT=0x0401

this_class 的值是常數表的索引,索引的 info 內保存類或接口名。例如類名為 com.sum.java.swing.SwingUtitlities2 info 保存為 com/sum/java/swing/SwingUtitlities2

super_class 的值是常數表的索引,索引的 info 內保存超類名,在 info 內保存形式和類名相同。

interfaces 是數組,數組個數為 interfaces_count ,數組內的元素為常數表的索引,索引的 info 內保存超接口名,在 info 內保存形式和類名相同。

field_info **fields 是類域數據的指針數組,指針數組個數為 fields_count ,結構體 field_info 定義如下:

struct field_info

{

????????????? u2 access_flags;??????????????? ? // 域修飾符掩碼

????????????? u2 name_index;???????????????? // 域名在常數表內的索引

????????????? u2 descriptor_index;??? ?????? // 域的描述符,其值是常數表內的索引

????????????? u2 attributes_count;?????????? // 域的屬性個數

????????????? attribute_info **attributes; // 域的屬性數據,即域的值

?

};

例如一個域定義如下:

private final static byte UNSET=127;

則該域的修飾符掩碼值為: ACC_PRIVATE | ACC_STATIC | ACC_FINAL=0x001A

常數表內 name_index 索引內保存數據為 UNSET ,常數表內 descriptor_index 索引內保存的數據為 B B 表示 byte, 其他類型參考《 Java 虛擬機規范》第四章 4.3.2 節)。 attributes_count 的值為 1 ,其中 attributes 是指針數組。指針數組個數為 attributes_count ,在此為 1 attribute_info 結構體如下:

struct attribute_info

{

????????????? u2 attribute_name_index;?? // 常數表內索引

????????????? u4 attribute_length;??????????? // 屬性長度

????????????? u1 *info;???????????????????????????? // 根據屬性類型不同而值不同

};?

attribute_info 可以轉換 (cast) 為多種類型 ConstantValue_attribute Exceptions_attribute LineNumberTable_attribute LocalVariableTable_attribute Code_attribute 等。

因為域的屬性只有一種: ConstantValue_attribute ,因此此結構體轉換為

struct ConstantValue_attribute

{

????????????? u2 attribute_name_index;??????? // 常數表內索引

????????????? u4 attribute_length;???????????????? // 屬性長度值,永遠為 2

????????????? u2 constantvalue_index;??????? ? // 常數表內索引,保存域的值

// 在此例中,常數表內保存的值為 127

};

method_info **methods 是方法數據的指針數組,指針數組個數為 methods_count ,結構體 method_info 定義如下:

struct method_info

{

????????????? u2 access_flags;?????????????????? // 方法修飾符掩碼

????????????? u2 name_index;?????????????????? // 方法名在常數表內的索引

????????????? u2 descriptor_index;??????????? // 方法描述符,其值是常數表內的索引

????????????? u2 attributes_count;???????????? // 方法的屬性個數

????????????? attribute_info **attributes;? // 方法的屬性數據,

// 保存方法實現的 Bytecode 和異常處理

};

例如一個方法定義如下:

public static boolean canAccessSystemClipboard(){

????????????? ...

}

access_flags 的值為 ACC_PUBLIC | ACC_STATIC =0x0009 ,常數表內 name_index 索引內保存數據為 canAccessSystemClipboard ,常數表內 descriptor_index 索引內保存數據為 ()Z ( 括號表示方法參數, Z 表示返回值為布爾型,詳細說明參照《 Java 虛擬機規范》第四章 4.3.2 ) attribute_info **attributes 是方法的屬性指針數組,個數為 attributes_count ,數組內保存的是常數表索引, info Code_attribute Exceptions_attribute

本文不解析方法內容,因此忽略 Code_attribute Exceptions_attribute 的內容。

?

ClassFile 結構體中的 attribute_info **attributes 是附加屬性數組指針,個數為 attributes_count ,本文只識別 SourceFile 屬性。

struct SourceFile_attribute

{

????????????? u2 attribute_name_index; // 常數表內索引

????????????? u4 attribute_length;????????? // 屬性長度值,永遠為 2

????????????? u2 sourcefile_index;???????? // 常數表內索引, info 保存源文件名

};

例如 com.sum.java.swing.SwingUtitlities2 類的源文件名為 SwingUtitlities2.java

????????????? 以上是本文需要解析的 Class 文件格式。

2.1.2 讀取數據

定義 CJavaClass 類完成解析 Class 文件,生成 Java 源程序字符串。使用 VC++ MFC CFile Class 文件讀取數據。 例如:用 16 進制編輯器打開 Class 文件,如圖 3 ,前 4 byte 分別是 CA FE BA BE ,使用 CFile::Read(tmp,sizeof(u4)) 讀取后, tmp 的值為 0xBEBAFECA ,所以需要位轉換。定義以下方法從文件讀取定長數據:

????????????? ????????????? void readu1(u1 *buff);

? void readu2(u2 *buff);

? void readu4(u4 *buff);

定義如下方法讀取變長數據。

void readun(void *buff,u4 len)

讀取的 u2 u4 的數據需要位轉換:

U1? [0]

U1 [1]

U1?? [1]

U1 [0]

U2

U1? [0]

U1 [1]

U1?? [3]

U4

U1 [2]

U1? [3]

U1 [2]

U1?? [0]

U1 [1]

調用 void readu4(u4 *buff); buff 的值為 0x CAFEBABE ,該值為 ClassFile magic ,識別該文件是 Java Class 文件。

?

3

????????????? magic 的后面是 Class 格式的版本號,圖 3 的版本為 0x00000030=0.48 。版本后面是常數表的元素個數,圖 3 的常數表的元素個數為 0xD2=210 個。常數表的元素個數之后如 ClassFile 結構體定義的常數表,類信息,接口信息,域信息,方法信息和附加屬性等。

2.2 生成 Java 源文件

????????????? 解析 Class 文件后,生產 ClassFile 結構體。遍歷該結構體數據,則可根據 Java 語言規范生成 Java 源文件。例如根據 ClassFile access_flags 值獲得 Java 類的修飾符,其中 access CArray<CString,CString&> ,保存類所有的修飾符

????????????? if((flag & ACC_PUBLIC )==ACC_PUBLIC)

????????????? {

????????????????????????????????????????? access.Add(CString("public"));

????????????? }

????????????? if((flag & ACC_PRIVATE)==ACC_PRIVATE)

????????????? {

????????????????????????????????????????? access.Add(CString("private"));

?

????????????? }

????????????? if((flag & ACC_PROTECTED)==ACC_PROTECTED)

????????????? {

????????????????????????????????????????? access.Add(CString("protected"));

?

????????????? }

2.3 顯示視圖

????????????? 將獲得的 Java 源代碼顯示在 MFC CScrollView 視圖非常簡單,可以添加一些關鍵字顏色,例如注釋顯示為草綠色等,如圖 4

4

3 .總結

????????????? 本文根據《 Java 虛擬機規范》開發了解析 Java Class 文件格式,并生成 Java 源代碼結構的工具。其優點是:

1. 脫離 Java 虛擬機或 Java 開發環境;

2. 可查閱沒有 Java 源代碼的 Class 文件的內容;

3. 為一些復雜的 Java Jar 包生成相同類名的替代類,方便開發調試。例如,用返回固定字符串的 java 源文件更換需要網絡鏈接的相同 java 類,有助于本地運行與調試。

缺點是:

1. 由于沒有反編譯 Bytecode ,工具生成的部分 Java 源文件需要手動添加一些 Java 屬性值;

2. Java 源文件內的所需要使用的 Java 方法內容需要程序員手動實現。

?

總結

以上是生活随笔為你收集整理的.class文件格式(java字节码文件的格式)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。