返回顶部
首页 > 资讯 > 后端开发 > Python >浅谈JVM之java class文件的密码本
  • 375
分享到

浅谈JVM之java class文件的密码本

2024-04-02 19:04:59 375人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录简介一个简单的classClassFile的二进制文件class文件的密码本magicversion常量池描述符access_flagsthis_class和super_clas

简介

机器可以读,人为什么不能读?只要我们掌握java class文件的密码表,我们可以把二进制转成十六进制,将十六进制和我们的密码表进行对比,就可以轻松的解密了。

下面,让我们开始这个激动人心的过程吧。

一个简单的class

为了深入理解java class的含义,我们首先需要定义一个class类:


public class JavaClassUsage {

    private int age=18;

    public void inc(int number){
        this.age=this.age+ number;
    }
}

很简单的类,我想不会有比它更简单的类了。

在上面的类中,我们定义了一个age字段和一个inc的方法。

接下来我们使用javac来进行编译。

idea有没有?直接打开编译后的class文件,你会看到什么?

没错,是反编译过来的java代码。但是这次我们需要深入了解的是class文件,于是我们可以选择 view->Show Bytecode:

当然,还是少不了最质朴的javap命令:

 javap -verbose JavaClassUsage

对比会发现,其实javap展示的更清晰一些,我们暂时选用javap的结果。

编译的class文件有点长,我一度有点不想都列出来,但是又一想只有对才能讲述得更清楚,还是贴在下面:

public class com.flydean.JavaClassUsage

  minor version: 0

  major version: 58

  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V

   #2 = Class              #4             // java/lang/Object

   #3 = NameAndType        #5:#6          // "<init>":()V

   #4 = Utf8               java/lang/Object

   #5 = Utf8               <init>

   #6 = Utf8               ()V

   #7 = Fieldref           #8.#9          // com/flydean/JavaClassUsage.age:I

   #8 = Class              #10            // com/flydean/JavaClassUsage

   #9 = NameAndType        #11:#12        // age:I

  #10 = Utf8               com/flydean/JavaClassUsage

  #11 = Utf8               age

  #12 = Utf8               I

  #13 = Utf8               Code

  #14 = Utf8               LineNumberTable

  #15 = Utf8               LocalVariableTable

  #16 = Utf8               this

  #17 = Utf8               Lcom/flydean/JavaClassUsage;

  #18 = Utf8               inc

  #19 = Utf8               (I)V

  #20 = Utf8               number

  #21 = Utf8               SourceFile

  #22 = Utf8               JavaClassUsage.java

{

  public com.flydean.JavaClassUsage();

    descriptor: ()V

    flags: ACC_PUBLIC

    Code:

      stack=2, locals=1, args_size=1

         0: aload_0

         1: invokespecial #1                  // Method java/lang/Object."<init>":()V

         4: aload_0

         5: bipush        18

         7: putfield      #7                  // Field age:I

        10: return

      LineNumberTable:

        line 7: 0

        line 9: 4

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0      11     0  this   Lcom/flydean/JavaClassUsage;

  public void inc(int);

    descriptor: (I)V

    flags: ACC_PUBLIC

    Code:

      stack=3, locals=2, args_size=2

         0: aload_0

         1: aload_0

         2: getfield      #7                  // Field age:I

         5: iload_1

         6: iadd

         7: putfield      #7                  // Field age:I

        10: return

      LineNumberTable:

        line 12: 0

        line 13: 10

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0      11     0  this   Lcom/flydean/JavaClassUsage;

            0      11     1 number   I

}

SourceFile: "JavaClassUsage.java"

ClassFile的二进制文件

慢着,上面javap的结果好像并不是二进制文件!

对的,javap是对二进制文件进行了解析,方便程序员阅读。如果你真的想直面最最底层的机器代码,就直接用支持16进制的文本编译器把编译好的class文件打开吧。

你准备好了吗?来吧,展示吧!

上图左边是16进制的class文件代码,右边是对16进制文件的适当解析。大家可以隐约的看到一点点熟悉的内容。

是的,没错,你会读机器语言了!

class文件的密码本

如果你要了解class文件的结构,你需要这个密码本。

如果你想解析class文件,你需要这个密码本。

学好这个密码本,走遍天下都......没啥用!

下面就是密码本,也就是classFile的结构。


ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

其中u2,u4表示的是无符号的两个字节,无符号的4个字节。

java class文件就是按照上面的格式排列下来的,按照这个格式,我们可以自己实现一个反编译器(大家有兴趣的话,可以自行研究)。

我们对比着上面的二进制文件一个一个的来理解。

magic

首先,class文件的前4个字节叫做magic Word

看一下十六进制的第一行的前4个字节:

CA FE BA BE 00 00 00 3A 00 17 0A 00 02 00 03 07 

0xCAFEBABE就是magic word。所有的java class文件都是以这4个字节开头的。

来一杯咖啡吧,baby!

多么有诗意的画面。

version

这两个version要连着讲,一个是主版本号,一个是次版本号。

00 00 00 3A

对比一下上面的表格,我们的主版本号是3A=58,也就是我们使用的是jdk14版本。

常量池

接下来是常量池。

首先是两个字节的constant_pool_count。对比一下,constant_pool_count的值是:

00 17

换算成十进制就是23。也就是说常量池的大小是23-1=22。

这里有两点要注意,第一点,常量池数组的index是从1开始到constant_pool_count-1结束。

第二点,常量池数组的第0位是作为一个保留位,表示“不引用任何常量池项目”,为某些特殊的情况下使用。

接下来是不定长度的cp_info:constant_pool[constant_pool_count-1]常量池数组。

常量池数组中存了些什么东西呢?

字符串常量,类和接口名字,字段名,和其他一些在class中引用的常量。

具体的constant_pool中存储的常量类型有下面几种:

每个常量都是以一个tag开头的。用来告诉JVM,这个到底是一个什么常量。

好了,我们对比着来看一下。在constant_pool_count之后,我们再取一部分16进制数据:

上面我们讲到了17是常量池的个数,接下来就是常量数组。

0A 00 02 00 03

首先第一个字节是常量的tag, 0A=10,对比一下上面的表格,10表示的是CONSTANT_Methodref方法引用。

CONSTANT_Methodref又是一个结构体,我们再看一下方法引用的定义:


CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

从上面的定义我们可以看出,CONSTANT_Methodref是由三部分组成的,第一部分是一个字节的tag,也就是上面的0A。

第二部分是2个字节的class_index,表示的是类在常量池中的index。

第三部分是2个字节的name_and_type_index,表示的是方法的名字和类型在常量池中的index。

先看class_index,0002=2。

常量池的第一个元素我们已经找到了就是CONSTANT_Methodref,第二个元素就是跟在CONSTANT_Methodref后面的部分,我们看下是什么:

07 00 04

一样的解析步骤,07=7,查表,表示的是CONSTANT_Class。

我们再看下CONSTANT_Class的定义:


CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

可以看到CONSTANT_Class占用3个字节,第一个字节是tag,后面两个字节是name在常量池中的索引

00 04 = 4, 表示name在常量池中的索引是4。

然后我们就这样一路找下去,就得到了所有常量池中常量的信息。

这样找起来,眼睛都花了,有没有什么简单的办法呢?

当然有,就是上面的javap -version, 我们再回顾一下输出结果中的常量池部分:

Constant pool:

   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V

   #2 = Class              #4             // java/lang/Object

   #3 = NameAndType        #5:#6          // "<init>":()V

   #4 = Utf8               java/lang/Object

   #5 = Utf8               <init>

   #6 = Utf8               ()V

   #7 = Fieldref           #8.#9          // com/flydean/JavaClassUsage.age:I

   #8 = Class              #10            // com/flydean/JavaClassUsage

   #9 = NameAndType        #11:#12        // age:I

  #10 = Utf8               com/flydean/JavaClassUsage

  #11 = Utf8               age

  #12 = Utf8               I

  #13 = Utf8               Code

  #14 = Utf8               LineNumberTable

  #15 = Utf8               LocalVariableTable

  #16 = Utf8               this

  #17 = Utf8               Lcom/flydean/JavaClassUsage;

  #18 = Utf8               inc

  #19 = Utf8               (I)V

  #20 = Utf8               number

  #21 = Utf8               SourceFile

  #22 = Utf8               JavaClassUsage.java

以第一行为例,直接告诉你常量池中第一个index的类型是Methodref,它的classref是index=2,它的NameAndType是index=3。

并且直接在后面展示出了具体的值。

描述符

且慢,在常量池中我好像看到了一些不一样的东西,这些I,L是什么东西?

这些叫做字段描述符:

上图是他们的各项含义。除了8大基础类型,还有2个引用类型,分别是对象的实例,和数组。

access_flags

常量池后面就是access_flags:访问描述符,表示的是这个class或者接口的访问权限。

先上密码表:

再找一下我们16进制的access_flag:

没错,就是00 21。 参照上面的表格,好像没有21,但是别怕:

21是ACC_PUBLIC和ACC_SUPER的并集。表示它有两个access权限。

this_class和super_class

接下来是this class和super class的名字,他们都是对常量池的引用。

00 08 00 02

this class的常量池index=8, super class的常量池index=2。

看一下2和8都代表什么:

#2 = Class              #4             // java/lang/Object

#8 = Class              #10            // com/flydean/JavaClassUsage

没错,JavaClassUsage的父类是Object。

大家知道为什么java只能单继承了吗?因为class文件里面只有一个u2的位置,放不下了!

interfaces_count和interfaces[]

接下来就是接口的数目和接口的具体信息数组了。

00 00

我们没有实现任何接口,所以interfaces_count=0,这时候也就没有interfaces[]了。

fields_count和fields[]

然后是字段数目和字段具体的数组信息。

这里的字段包括类变量和实例变量。

每个字段信息也是一个结构体:


field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

字段的access_flag跟class的有点不一样:

这里我们就不具体对比解释了,感兴趣的小伙伴可以自行体验。

methods_count和methods[]

接下来是方法信息。

method结构体:


method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

method访问权限标记:

attributes_count和attributes[]

attributes被用在ClassFile, field_info, method_info和Code_attribute这些结构体中。

先看下attributes结构体的定义:


attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];
}

都有哪些attributes, 这些attributes都用在什么地方呢?

其中有六个属性对于Java虚拟机正确解释类文件至关重要,他们是:
ConstantValue,Code,StackMapTable,BootstrapMethods,NestHost和NestMembers。

九个属性对于Java虚拟机正确解释类文件不是至关重要的,但是对于通过Java SE PlatfORM的类库正确解释类文件是至关重要的,他们是:

Exceptions,InnerClasses,EnclosingMethod,Synthetic,Signature,SourceFile,LineNumberTable,LocalVariableTable,LocalVariableTypeTable。

其他13个属性,不是那么重要,但是包含有关类文件的元数据。

总结

最后留给大家一个问题,java class中常量池的大小constant_pool_count是2个字节,两个字节可以表示2的16次方个常量。很明显已经够大了。

以上就是浅谈JVM之java class文件的密码本的详细内容,更多关于JVM之java class文件的密码本的资料请关注编程网其它相关文章!

--结束END--

本文标题: 浅谈JVM之java class文件的密码本

本文链接: https://lsjlt.com/news/127432.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 浅谈JVM之java class文件的密码本
    目录简介一个简单的classClassFile的二进制文件class文件的密码本magicversion常量池描述符access_flagsthis_class和super_clas...
    99+
    2024-04-02
  • JVM真香系列之如何学习Java文件到.Class文件
    本篇内容主要讲解“JVM真香系列之如何学习Java文件到.Class文件”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JVM真香系列之如何学习Java文件到.Class文件”吧!什么是JVMJV...
    99+
    2023-06-15
  • 浅谈Java安全编码之文件和共享目录的安全性
    目录一、linux下的文件基本权限二、linux文件的特殊权限2.1、Set UID 和 Set GID2.2、Sticky Bit2.3、SUID/SGID/SBIT权限设置三、文...
    99+
    2024-04-02
  • 深入浅析Java中的class文件格式
    这期内容当中小编将会给大家带来有关深入浅析Java中的class文件格式,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。class文件中的fields_count和fieldsfields_count描述的...
    99+
    2023-05-31
    java class ava
  • 浅谈Java文件被执行的历程
    目录Java的编译过程一个例子第一步第二步Java的编译过程 Java程序从源文件创建到程序运行要经过两大步骤 1、源文件由编译器编译成字节码(ByteCode) 2、字节码由ja...
    99+
    2024-04-02
  • 深入浅析Java中 class文件的数据类型
    深入浅析Java中 class文件的数据类型?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。CONSTANT_Integer_info一个常量池中的CONSTANT_Intege...
    99+
    2023-05-31
    java class ava
  • 深入浅析Java中class文件格式的属性
    这期内容当中小编将会给大家带来有关深入浅析Java中class文件格式的属性,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。class文件中的attributes_count和attributesattri...
    99+
    2023-05-31
    java class ava
  • 浅谈Java中File文件的创建以及读写
    目录1.创建一个文件2.创建一个文件夹3.创建同目录下文件4.删除文件或空文件夹5.递归删除所有文件(包括子文件)6.读取txt文件内容,流操作要用try-catch(字符流)7.读...
    99+
    2024-04-02
  • JVM中Java字节码文件的示例分析
    小编给大家分享一下JVM中Java字节码文件的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!每一个class字节码文件都唯一对应一个类或接口,class文...
    99+
    2023-06-02
  • 浅谈一下Java为什么不能使用字符流读取非文本的二进制文件
    目录读取文件为什么会这样呢?总结读取文件 刚学Java的IO流部分时,书上说只能使用字节流去读取图片、视频等非文本二进制文件,不能使用字符流,否则文件会损坏。所以我就一直记住这一点了...
    99+
    2023-05-15
    Java字符流 字符流读取非文本 Java二进制文件
  • Java可视化之实现文本的加密和解密
    目录一、题目二、要求三、分析四、界面规划五、功能实现5.1 确定功能实现5.2 退出功能实现5.3 加密文本的产生5.4 密码文件的保存5.5 密码文件的解密5.6 <<...
    99+
    2024-04-02
  • Java实现Excel文件加密解密的示例代码
    目录概述示例大纲工具Java代码示例示例1加密工作簿示例2解密工作簿示例3加密工作表示例4加密工作表指定数据范围示例5设置工作表公式隐藏示例6解密Excel工作表概述 设置excel...
    99+
    2024-04-02
  • Java探索之Thread+IO文件的加密解密的示例分析
    这篇文章主要为大家展示了“Java探索之Thread+IO文件的加密解密的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java探索之Thread+IO文件的加密解密的示例分析”这篇文章...
    99+
    2023-05-30
    java io流
  • java实现获取文本文件的字符编码
    一、认识字符编码:Java中String的默认编码为UTF-8,可以使用以下语句获取:Charset.defaultCharset();Windows操作系统下,文本文件的默认编码为ANSI,对中文Windows来说即为GBK。例如我们使用...
    99+
    2021-11-01
    java 实现 获取 文本文件 字符编码
  • Java基础之删除文本文件中特定行的内容
    目录一、问题的产生二、解决思路三、具体解决方法四、总结一、问题的产生 基于I/O流编写的图书馆管理系统 在最近使用I/O流写图书馆管理系统中管理员对图书和用户的管理操作时,遇到了需要...
    99+
    2024-04-02
  • java获取一个文本文件的编码(格式)信息
    前言: 文本文件是我们在windows平台下常用的一种文件格式, 这种格式会随着操作系统的语言不同,而出现其默认的编码不同 那么如何使用程序获取“文本文件”的...
    99+
    2024-04-02
  • 云服务器访问本地文件夹怎么设置的密码
    如果您要访问的是一个本地文件夹,但您忘记了密码,以下是一个基本的方法,可以将密码更改为只有您本人知道的字符。 打开您的防火墙软件,并在其中输入一个新的路由器IP地址,以及一个新的访问控制列表。 然后,请确保您启用了“文件夹和打印机”和“...
    99+
    2023-10-27
    文件夹 密码 服务器
  • 云服务器访问本地文件夹怎么设置的密码呢
    一、选择合适的密码 在云服务器上设置密码的过程如下: 选择一个安全的密码:选择一个足够强度的密码,最好由数字、字母和符号组成,不要使用易于猜测的字符。 使用密码管理器:在本地计算机上安装密码管理器,以便可以轻松地记住和管理密码。密码管理...
    99+
    2023-10-28
    文件夹 密码 服务器
  • 利用Java怎么对比两个文本文件的相同与不同之处
    本篇文章给大家分享的是有关利用Java怎么对比两个文本文件的相同与不同之处,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。使用需求:文件1里面是需要比较的内容,文件2是被比较的文...
    99+
    2023-05-31
    java ava
  • 云服务器访问本地文件夹怎么设置的密码是多少
    1. 为什么要设置密码? 在云服务器上访问本地文件夹时,设置密码是一种常见的安全措施。通过设置密码,您可以确保只有授权的用户能够访问和修改您的本地文件夹。这可以防止未经授权的访问和潜在的数据泄露。 2. 如何设置密码? 要设置密码,您可以...
    99+
    2023-10-27
    文件夹 密码 服务器
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作