`

class文件检验器

阅读更多

     class文件检验器实现的安全目标之一就是程序的健壮性。如果某个有漏洞的编译器,或是某个聪明的黑客,产生了一个class文件,而这个class文件中包含了一个方法,这个方法的字节码中含有一条跳转到方法之外的指令,那么,一但这个方法被调用,它将导致虚拟机的崩溃。所以,出于对健壮性的考虑.由虚拟机检验它装载的字节码的完整性是非常重要的。
      Java虚拟机的class文件检验器在字节码执行之前,必须完成大部分检验工作。它只在执行前而不是在执行中对字节码进行一次分析(并检验它的完整性),每一次遇到一个跳转指令时都进行检验。作为字节码确认工作的一部分,虚拟机将确认所有的跳转指令会到达另一条合法的指今,而且这条指令是在这个方法的字节码流中的。在大多数情况下,在执行前就对所有字节码进行一次检查,对于保证健壮性来说就足够了,而不必在它运行时每次都检验每一条字节码指令。
      class文件检验器要进行四趟独立的扫描来完成它的操作。第一趟扫描是在类被装载时进行的,在这次扫描中,class文件检验器检查这个class文件的内部结构,以保证它可以被安全地编译。第二和第三趟扫描是在连接过程中进行的,在这两次扫描中,class文件检验器确认类型数据遵从java编程语言的语义,包括检验它所包含的所有字节码的完整性。第四趟扫描是在进行动态连接的过程中解析符号引用时进行的,在这次扫描中,class文件检验器确认被引用的类、字段以及方法确实存在。
第一趟:class文件的结构检查
      在第一趟扫描中,对每一段将被当作类型导入的字节序列,class文件检验器都会确认它是否符合java class文件的基本结构。在这次扫描中,检验器将进行许多检查,例如每个class文件必须以四个同样的字节开始:魔数OxCAFEBABE。这个魔数的用处是让class文件分析器很容易分辨出某个文件有明显问题而加以拒绝,这个文件可能是被破坏了的class文件,或者是压根儿就不是class文件。这样,class文件检验器所做的第一件事极可能就是检查导入的文件是否是以OxCAFEBABE开头的。检验器还必须确认在class文件中声明的主版本号和次版本号,这个版本号必须在这个java虚拟机实现可以支持的范围之内。
      而且,在第一趟扫描中,class文件检验器必须确认这个class文件没有被删节,尾部也没有附带其他的字节。虽然不同的class文件有不同的长度,但是在class文件中包含的每一个组成部分都声明了它的长度和类型。检验器可以使用组成部分的类型和长度来确定整个class文件的正确的总长度。用这种方法,它就可以检查一个装入的文件,其长度是否和它里面的内容相一致
      第一趟扫描的主要目的就是保证这个字节序列正确地定义了一个新类型,它必须遵从java的class文件的固定格式,这样它才能被编译成在方法区中的〔基于实现的)内部数据结构。第二、第三和第四的扫描不是在符合class文件格式的二进制数据上进行的,而是在方法区中的、由实现决定的数据结构上进行的。
第二趟:类型数据的语义检查
      在第二趟扫描中,class文件检验器进行的检查不需要查看字节码,也不需要查看和装载任何其他类型。在这趟扫描中,检验器查看每个组成部分,确认它们是否是其所属类型的实例,它们的结构是否正确。例如,方法描述符〔它的返回类型,以及参数的类型和个数)在class文件中被存储为一个字符串.这个字符串必须符合特定的上下文无关文法。检验器对每个组成部分进行检查的目的之一是,为了确认某个方法描述符都是符合特定语法的、格式正确的字符串。
另外,class文件检验器检查这个类本身是否符合特定的条件,它们是由java编程语言规定的。例如,检验器强制规定除Object类以外的所有类,都必须有一个超类。在第二趟的扫描中,检验器还要检查final类(最终的)类没有被子类化,而且final方法没有被覆盖。还要检查常量池中的条目是合法的,而且常量池的所有索引必须指向正确类型的常量池条目。也就是说, class文件检验器在运行时检查了一些java语言应该在编译时遵守的强制规则。因为检验器并不能确定class文件是否是由一个善意的、没有漏洞的编译器产生的,所以它会检查每个class文件,以确保这些规则得到遵守。
第三趟:字节码验证
      class文件检验器成功地进行了两趟检查后,它将把注意力放在字节码上,这一趟扫描被称为“字节码验证”。在这趟扫描中,Java虚拟机对字节流进行数据流分析,这些字节流代表的是类的方法。为了理解字节码检验器,必须对字节码和栈帧有一定的了解。
      字节码流代表了Java的方法,它是由被称为操作码的单字节指令组成的序列,每一个操作码后都跟着一个或多个操作数。操作数用于在Java虚拟机执行操作码指令时捉供所需的额外的数据。执行字节码时,依次执行每个操作码,这就在Java虚拟内构成了执行的线程。每一个线程被授予自己的java栈,这个栈是由不同的栈帧构成的。每一个方法调用将获得一个自己的栈帧———栈帧其实就是一个内存片断,其中存储着局部变量和计算的中间结果。在栈帧中,用于存储方法的中间结果的部分被称为该方法的操作数栈。操作码和它的(可选的)操作数可能指存储在操作数栈中的数据,或存储在方法栈帧中的局部变量中的数据。这样,在执行一个操作码时,除了可以使用紧随其后的操作数,虚拟机还可以使用操作数栈中的数据,或局部变量中的数据,或是两者都用。
      字节码检验器要进行大量的检查,以确保采用任何路径在字节码流中都得到一个确定的操作码,确保操作数栈总是包含正确的数值以及正确的类型。它必须保证局部变量在赋予合适的值以前不能被访向,而且类的字段中必须总是被赋予正确类型的值,类的方法被调用时总是传递正确数值和类型的参数。字节码检验器还必须保证每一个操作码都是合法的,即每一个操作码都有合法的操作数,以及对每一个操作码,合适类型的数值位于局部变量中或是在操作数栈中。这些仅仅是字节码检验器所做的大量检验工作中的一小部分,在整个检验过程通过后,它就能保证这个字节码流可以被Java虚拟机安全地执行。
      字节码检验器并不试图检测出所有的安全问题。如果要这样做的话,它将会遇到‘停机问题‘。停机问题是计算机科学领域的一个著名论题:即不可能写出一个程序,用它来判断作为其输入而读入的某个程序在执行时是否停机。一个程序是否会停机被称为是程序的“不可判定“特性,因为不可能写出一个程序,让它100%地告诉你任何一个给定的程序是否含有这种特性。停机问题的不可判定性可以扩展成计算机程序的许多特性,如一个java字节码的的集合能否被虚拟机安全的执行。
      字节码检验器处理停机问题的方法是,不去试图精确地让每个安全的程序都通过检查。虽然不能写出一个程序来判定任何给定程序是否会停机,但是可以写出一个简单的程序,让它只是识别出某些一定会停机的程序。例如,如果一个程序的第一条指令就是停机,那么,这个程序一定可以停机。如果一个程序内没有循环,它也一定可以停机.如此等等。同样,虽然不可能写出一个能扫描检查所有字节码流是否能被虚拟机安全执行的检验器,但是可以写出一个能让其中一部分安全的字节码流通过的检验器。Java的字节码检验器恰恰就是这么做的。这个检验器检查确认读入的每一个字节码集合是否符合一个特定的规则集合。如果一个字节码集合能够遵从所有这些舰则,那么检验器就知道它可以被虚拟机安全地执行。如果不是,那么,这些字节码可能可以被虚拟机安全地执行,也可能不能安全地执行。这样,通过识别一些安全的字节码流,但不是全部,检验器就绕过了停机问题。由于字节码检验器强制检查的特性,只要定义好规则,任何程序只要可以用java程序语言书写,编译器就可以确保编译出来的字节码可以被检验器通过。有些程序虽然不能用java编程语言源代码表达出来,但仍可以通过检验器的位验。另外还有些程序(也不能用Java代码表示),它们虽然实际上也能被java虚拟机安全地执行,却不能通过检验器的检验。
      在第一、第二、第三趟扫描中,class文件检验器可以保证导人的class文件构成合理,内在一致,符合Java编程语言的限制条件,并且包含的字节码可以被java虚拟机安全地执行。如果class文件检验器发现其中任何一点不正确.它将会抛出一个错误,这个class文件将不会被程序使用。
第四趟:符号引用的加证
     在动态连接的过程中,如果包含在一个class文件中的符号引用被解析时,class文件检验器将进行第四趟检查。在这趟检查中,Java虚拟机将追踪那些引用一从被验证的class文件到被引用的class文件,以确保这个引用是正确的。因为第四趟扫描必须检查被检测的class文件以外的其他类,所以这次扫描可能需要装载新的类。大多数Java虚拟机的实现采用延迟装载类的策略.直到类真正地被程序使用时才装载。即使一个实现确实预先装载了这些类,这是为了加快装载过程的速度,那它还是会表现为延迟装载。例如,如果java虚拟机在预先装载中发现它不能找到某个特定的被引用类,它并不在当时抛出NoClassDefFoundError错误,而是直到(或者除非)这个被引用类首次被运行程序使用时才抛出。这样,如果Java虚拟机进行预先连接,第四趟扫描可以紧随第三趟扫描发生。但是如果java虚拟机在某个符号引用第一次使用时才进行解析,那么第四趟扫描将在第三趟扫描以后很久、当字节码被执行时才进行。
      class文件检验器的第四趟扫描仅仅是动态连接过程的一部分。当一个class文件被装载时,它包含了对其他类的符号引用以及它们的字段和方法。一个符号引用是一个字符串,它给出了名字,并且可能还包含了其他关于这个被引用项的信息—-这些信息必须足以惟一地识别一个类、字段或方法。这样,对于其他类的符号引用必须给出这个类的全名;对于其他类的字段的符号引用必须给出类名、字段名以及字段描述符;对于其他类中的方法的引用必须给出类名、方法名以及方法的描述符。
      动态连接是一个将符号引用解析为直接引用的过程。当java虚拟机执行字节码时,如果它遇到一个操作码,这个操作码第一次使用一个指向另一个类的符号引用,那么虚拟机就必须解析这个符号引用。在解析时,虚拟机执行两个基本任务:
          l)查找被引用的类(如果必要的话就装载它)。 
         2)将符号引用替换为直接引用,例如一个指向类,字段或方法的指针或偏移量。
      虚拟机必须记住这个直接引用,这样当它以后再次遇到相同的引用时,它就可以立即使用这个直接引用,而不必花时间再次解析这个符号引用了。
      当Java虚拟机解析一个符号引用时,class文件检验器的第四趟扫描确保了这个引用是合法的。当这个引用是个非法引用时---例如,这个类不能被装载,或这个类的确存在,但是不包含被引用的字段或方法--class文件检验器将抛出一个错误。
      再以Volcano类为例。如果Volcano类中的某个方法调用了名为Lava的类中的某个方法,这个Lava中的方法的全名和描述符将包含在Volcano的class文件的二进制数据中。当Volcano的方法在执行过程中第一次调用Lava的方法时,Java虚拟机必须确认Lava中存在这个方法,并且这个方法的名字和描述符与Volcano类中期待的相匹陪。如果这个符号引用(类名、方法名和描述符)是正确的,那么,虚拟机将把它替换为一个直接引用,例如一个指针,从那时开始将使用这个指针。但如果Volcano类中的符号引用不能匹配Lava类中的任何方法时,第四趟扫描验证失败,Java虚拟机将抛出一个NoSuchMethodError。

 

分享到:
评论

相关推荐

    Class文件反编译工具

    在某些情况下,我们可能需要查看或理解这些二进制文件的原始Java代码,这时就需要用到"Class文件反编译工具"。 "Class文件反编译工具"是一种专门用来将`.class`和`.jar`文件转换回可读的Java源代码格式的软件。这种...

    ClassFinal-java class文件安全加密工具

    在Java应用开发中,源代码的保护至关重要,因为Java的字节码(class文件)是可被反编译的,这可能导致源代码泄露、恶意篡改等安全风险。ClassFinal通过特定的加密算法和混淆技术,对Java类文件进行处理,使得未经...

    class文件热加载,上传class文件实现热加载

    - 在热加载场景下,自定义类加载器通常会监听某个文件系统或网络资源的变化,一旦检测到新版本的class文件,就立即加载。 3. **热加载原理**: - 热加载的核心是替换旧的类定义,而不是重新启动应用。这需要在...

    class文件分析

    在Android应用开发中,Java语言是主要的编程语言,而.class文件是Java源代码编译后的产物,它是Java字节码的载体,包含了程序的结构和指令。在Android系统中,.class文件并不直接运行,而是会被转换为.dex(Dalvik ...

    class文件版本查看器

    闲暇时写的小东西,路过的可以看看.查看class文件编译时使用的jdk版本.没技术含量,纯粹为了查看方便,使用UltraEdit一样可以看16进制来换算.

    YOLO 数据集:9种岩石检测【包含划分好的数据集、类别class文件、数据可视化脚本】

    项目包含:9种岩石检测【包含划分好的数据集、类别class文件、数据可视化脚本】,数据保存按照YOLOV5文件夹保存,可直接用作目标检测数据集,无需额外处理。 图像分辨率为640*640的大分辨率RGB图片,数据集为各种...

    Jvm之用C#解析class文件

    本篇将深入探讨如何使用C#语言来解析Java的class文件,这是一种跨语言的技术应用,有助于增强开发者对Java字节码的理解和操作能力。 首先,我们需要了解Java类文件的结构。一个`.class`文件是二进制格式的,包含了...

    class汉化工具 class汉化工具

    在IT行业中,"class汉化工具"通常指的是用于对Java字节码(.class文件)进行汉化的工具。这类工具的主要目的是帮助开发者或用户将Java程序中的英文资源转化为中文,以便于在中国等中文为主要语言的地区更好地使用和...

    YOLO 数据集:夜间车辆、行人检测(4类)【包含划分好的数据集、类别class文件、数据可视化脚本】

    数据为黑夜背景下的人群、车辆检测,保存按照YOLOV5文件夹保存,可直接用作yolo检测。 标注格式为:classes,x_centre、y_centre、w、h (yolo的相对坐标标注) 【类别】:人、自行车、汽车、狗(4类) 数据分为...

    YOLO 数据集:家具检测(3类)【包含划分好的数据集、类别class文件、数据可视化脚本】

    数据保存按照YOLOV5文件夹保存,可直接用作yolo检测。 标注格式为:classes,x_centre、y_centre、w、h (yolo的相对坐标标注) 【数据集类别】3类别:沙发、椅子、桌子 数据分为分为训练集和验证集: 训练集...

    编译class不用重启tomcat

    在传统的Java Web开发中,每当修改了Java类文件(.java),需要通过IDE重新编译生成.class文件,然后停止Tomcat,重新部署应用,最后启动Tomcat来查看改动效果。这个过程既耗时又打断了开发流程。为了解决这个问题,...

    贪吃蛇小游戏+源码+class文件

    在这个项目中,我们看到一个基于Java实现的贪吃蛇游戏,包括源码和编译后的class文件。下面我们将深入探讨这个游戏背后的编程知识点。 首先,`JFrame` 类是Java Swing库中的一个关键组件,它用于创建窗口应用的基础...

    java热加载Class文件.zip

    Java热加载Class文件技术是一种在不重启应用服务器的情况下更新或替换正在运行的Java类的方法,这对于开发者来说是一项非常实用的功能,因为它极大地提高了开发效率。在传统的开发过程中,修改代码后通常需要停止、...

    在Eclipse中反编译Class文件完全详解

    如果Eclipse检测到该文件是Class文件,它会自动调用JD-Eclipse进行反编译,并显示源代码。 需要注意的是,反编译并不总是能够完美地恢复原始的源代码,特别是当原代码包含复杂的编译优化或元数据时。此外,如果...

    javaclass反编辑器

    7. **安全分析**:在安全领域,分析.class文件可能用于检测恶意代码,或者逆向工程以理解第三方库的工作方式。 8. **软件逆向工程**:开发者可能会使用这类工具来理解无法获取源代码的第三方库,以便于修改、优化或...

    JavaClass二进制文件加密专家

    3. **动态加载与解密**:为了进一步增强安全性,有些加密工具会在程序运行时动态地加载和解密Class文件,这样即使有人获取到加密后的文件,也无法直接执行,因为缺少解密的关键环节。 4. **数字签名**:添加数字...

    实现tomcat热更新class文件.docx

    为了解决这个问题,可以配置Tomcat实现热更新class文件,使得修改后的Java类在不重启服务器的情况下就能立即生效。下面将详细介绍如何实现这一功能。 首先,我们需要理解Tomcat的工作原理。当一个Web应用被部署到...

    YOLO 目标检测数据集:农作物害虫检测(4类别)【包含划分好的数据集、类别class文件、数据可视化脚本】

    项目包含:农作物害虫检测(4类别)【包含划分好的数据集、类别class文件、数据可视化脚本】,数据保存按照YOLOV5文件夹保存,可直接用作目标检测数据集,无需额外处理。 图像分辨率为640*640的大分辨率RGB图片,...

    YOLO 数据集:草莓成熟度检测【包含训练集、验证集、对应标签、class文件】

    YOLO 数据集:草莓成熟度检测【包含训练集、验证集、对应标签、class文件】 数据保存按照YOLOV5文件夹保存,可直接用作yolo检测。 标注格式为:classes,x_centre、y_centre、w、h (yolo的相对坐标标注) 类别个数...

    一个简单的class文件解析

    在Java编程语言中,`class`文件是一种二进制文件,它包含了编译后的Java代码。这个简单的`class`文件解析的主题将引导我们深入理解Java虚拟机(JVM)的工作原理,以及如何通过工具来分析这些文件。我们将探讨类文件...

Global site tag (gtag.js) - Google Analytics