`
RednaxelaFX
  • 浏览: 3049659 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

一个通不过Java字节码校验的例子

    博客分类:
  • Java
阅读更多
一般我们写Java源码,用Java编译器编译出.class文件,是不会碰到校验失败的状况的,因为正常的Java编译器都会小心对待生成的代码。所以,想要看到校验失败的状况,很容易的一个办法就是自己生成不合法的字节码。

这里我用了ObjectWeb的ASM来生成字节码。可以从官网下载asm-3.1.jar,并保证其在编译和运行下面这个程序时在classpath上。
(本来是很想顺便试试Charles O. Nutter写的bitescript库,不过惰性上来了,懒得去下载……下次吧,下次)
import java.io.FileOutputStream;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class TestASM implements Opcodes {
    public static void main(String[] args) throws Exception {
        ClassWriter cw = new ClassWriter(0);
        cw.visit(
            V1_5,               // class format version
            ACC_PUBLIC,         // class modifiers
            "TestVerification", // class name fully qualified name
            null,               // generic signature
            "java/lang/Object", // super class fully qualified name
            new String[] { }    // implemented interfaces
        );
        
        MethodVisitor mv = cw.visitMethod(
            ACC_PUBLIC, // access modifiers
            "foo",      // method name
             "()V",     // method descriptor
             null,      // generic signature
             null       // exceptions
        );
        mv.visitCode();
        mv.visitInsn(FCONST_0);
        mv.visitVarInsn(FSTORE, 1);
        mv.visitVarInsn(ILOAD, 1);
        mv.visitVarInsn(ISTORE, 1);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 2);
        mv.visitEnd(); // end method
        
        cw.visitEnd(); // end class
        
        byte[] clz = cw.toByteArray();
        FileOutputStream out = new FileOutputStream("TestVerification.class");
        out.write(clz);
        out.close();
    }
}


运行该程序后,得到的是TestVerification.class文件,其内容是:
public class TestVerification extends java.lang.Object
  minor version: 0
  major version: 49
  Constant pool:
const #1 = Asciz        TestVerification;
const #2 = class        #1;     //  TestVerification
const #3 = Asciz        java/lang/Object;
const #4 = class        #3;     //  java/lang/Object
const #5 = Asciz        foo;
const #6 = Asciz        ()V;
const #7 = Asciz        Code;

{
public void foo();
  Code:
   Stack=1, Locals=2, Args_size=1
   0:   fconst_0
   1:   fstore_0
   2:   iload_0
   3:   istore_0
   4:   return

}

可以看到,foo()里代码先把float类型的常量0.0压到求值栈上(fconst_0),然后将它弹出并保存到局部存储区的第一格(fstore_0)。接下来从局部存储区的第一格取出一个int类型的值压到求值栈上(iload_0),再将其弹出并再次保存到局部存储区的第一格(istore_0)。

要是硬要用Java来表示这个.class文件里的逻辑,大概类似这样:
public class TestVerification {
    public void foo() {
        float a = 0;
        ((int) a) = a;
    }
}

很明显这没办法用Java表达出来……

上面代码中,局部存储区的第一格就在同一个方法里前后用于保存了float和int类型的值,破坏了类型安全。JVM为了保证类型安全,要求局部存储区里每格在上一次store与下一次load之间只能保存固定类型的值,load/store与对应的格的类型必须匹配;上一次load与下一次store的类型则并不要求一致。

运行这个程序会导致校验错误:
D:\temp_code>java TestVerification
Exception in thread "main" java.lang.VerifyError: (class: TestVerification, method: foo signature: ()V) Register 1 contains wrong type
Could not find the main class: TestVerification.  Program will exit.

于是JVM的类加载器先抱怨校验失败,然后拒绝加载这个main()方法,后面就连锁抱怨找不到main类。
分享到:
评论
5 楼 changcheng 2013-05-31  
RednaxelaFX 写道
changcheng 写道
问题找到了:

23:  iload_1 应该使用 aload_1

用JDK8的话在通不过bytecode verification时JVM会报出更详细的错误。可以下载现在的试用版来试试
http://openjdk.java.net/jeps/136


好的,我试试。这样会很方便,哈哈!
4 楼 RednaxelaFX 2013-05-23  
changcheng 写道
问题找到了:

23:  iload_1 应该使用 aload_1

用JDK8的话在通不过bytecode verification时JVM会报出更详细的错误。可以下载现在的试用版来试试
http://openjdk.java.net/jeps/136
3 楼 changcheng 2013-05-23  
问题找到了:

23:  iload_1 应该使用 aload_1
2 楼 changcheng 2013-05-23  
//==== 补充 javap -c
public void setHSFContainer(java.lang.Object);
  Code:
   0:   ldc     #2; //class com/taobao/hsf/log/impl/CallbackComponent
   2:   ldc     #51; //String setHSFContainer
   4:   ldc     #52; //String (Ljava/lang/Object;)V
   6:   invokestatic    #56; //Method com/tb/xman/common/hook/XManMethodCallBack.needHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Z

   9:   istore_2
   10:  iload_2
   11:  ifeq    29
   14:  ldc     #57; //int 1
   16:  anewarray       #4; //class java/lang/Object
   19:  astore_3
   20:  aload_3
   21:  ldc     #58; //int 0
   23:  iload_1
   24:  aastore
   25:  aload_3
   26:  invokestatic    #61; //Method com/tb/xman/common/hook/XManMethodCallBack.beforeMethod:([Ljava/lang/Object;)V
   29:  aload_0
   30:  aload_1
   31:  putfield        #20; //Field container:Ljava/lang/Object;
   34:  invokestatic    #23; //Method com/tb/xman/common/hook/XManMethodCallBack.beforeReturn:()V
   37:  return
1 楼 changcheng 2013-05-23  
//====== asm 生成的代码
public void setHSFContainer(Object container)
{
boolean flag = XManMethodCallBack.needHook(com/tb/hsf/log/impl/CallbackComponent, "setHSFContainer", "(Ljava/lang/Object;)V");
if(flag)
{
    Object aobj[] = new Object[1];
    aobj[0] = container;
    XManMethodCallBack.beforeMethod(aobj);
}
this.container = container;
XManMethodCallBack.beforeReturn();
}

//====== exception:

Exception in thread "main" java.lang.VerifyError: (class: com/tb/hsf/log/impl/CallbackComponent, method: setHSFContainer signature: (Ljava/lang/Object;)V) Register 1 contains wrong type
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
at java.lang.Class.getConstructor0(Class.java:2699)
at java.lang.Class.newInstance0(Class.java:326)
at java.lang.Class.newInstance(Class.java:308)
at com.tb.hsf.container.HSFContainer.initCallbackService(HSFContainer.java:242)
at com.tb.hsf.container.HSFContainer.start(HSFContainer.java:208)
at runjettyrun.Bootstrap.main(Bootstrap.java:220)


这个是什么原因呢?

相关推荐

    java实现 crc16校验工具和代码

    在这个例子中,`calculateCRC`方法接收一个字节数组作为输入,逐位进行CRC计算。`POLYNOMIAL`常量代表生成多项式,`crc`变量用于存储CRC寄存器的值。在`main`方法中,可以使用这个类来计算特定数据的CRC16校验码。 ...

    Java 实现CRC码算法(含实现原理和步骤)

    其核心在于利用特定的数学方法(通常基于二进制多项式运算)来计算一个校验值,该值随后被附加到原始数据之后一同发送。接收端收到数据后,同样使用相同的算法计算接收到的数据的CRC校验值,并与接收到的CRC值进行...

    CRC校验例子

    CRC(Cyclic Redundancy Check,循环冗余校验)是一种广泛应用于数据通信领域中的错误检测技术,它通过计算一个固定长度的校验码并将其附加到原始数据之后,接收方通过对收到的数据执行相同的计算来验证数据传输过程...

    java MD5加密 实例 例子

    在这个例子中,我们首先定义了一个字符串`inputString`,然后使用`getInstance("MD5")`创建了MD5哈希实例。接着,通过`digest()`方法计算出`inputString`的MD5摘要,这是一个字节数组。为了将字节转换成人类可读的...

    corejava基础重要知识点总结

    = 保镖 = 字节码校验器 = ByteCode Verifier = 翻译 = 解释执行器 = Interfreter 2:安全 健壮 电力 电信 银行 都会有限考虑使用java实现 3:免费 开源 4:简单 语法简单:c++-- (取其精华 去其糟粕) ...

    md5码 java 程序

    MD5码,全称为Message-Digest Algorithm 5,是一种广泛使用的加密散列函数,产生一个128位(16字节)的散列值,通常以32个十六进制数字的形式表示。在Java编程语言中,MD5被用作生成数据校验和,以验证文件或字符串...

    java 段点续传 例子

    下面将详细探讨Java如何实现这一功能。 在Java中,实现断点续传通常涉及到以下几个关键知识点: 1. **文件IO操作**:Java的`java.io`包提供了丰富的文件输入/输出流类,如`FileInputStream`、`FileOutputStream`、...

    Java语言程序设计第二版习题解答

    - **Java虚拟机**:是一种虚拟计算平台,能够在各种操作系统上运行Java字节码。它是Java实现跨平台的关键。 - **Java字节码**:是Java源代码编译后的中间代码,是一种与平台无关的格式,可以在任何安装了Java虚拟机...

    纯java流实现的邮件发送

    Java邮件发送是一个常见的任务,尤其在企业级应用中,它经常用于发送通知、报告或附件。本教程将深入探讨如何使用纯Java流实现邮件发送功能,重点在于理解邮件协议和如何处理文件传输。 首先,我们需要了解JavaMail...

    java MD5机密实例 例子

    在Java中,MD5常用于密码加密、文件校验等方面,因为其不可逆性,可以有效防止原始数据被恢复,增加了数据的安全性。 本实例是关于如何在Java中使用MD5进行数据加密的实践。以下将详细介绍如何通过Java实现MD5加密...

    分享JavaScript与Java中MD5使用两个例子

    标题《分享JavaScript与Java中MD5使用两个例子》中的知识点涉及了如何在JavaScript和Java语言中使用MD5加密算法,以及如何将字符串转换为MD5格式。MD5是一种广泛使用的密码散列函数,它可以产生一个128位的散列值...

    7、垃圾回收与JAVA运行过程借鉴.pdf

    Java的字节码校验器(A选项)确实加载了执行程序所需的类,但它不是安全相关的描述。正确的是,执行代码由运行时解释器完成(B选项),在运行时字节码被加载、验证并在解释器中运行(C选项)。类加载器(D选项)通过...

    java串口操作源码

    Java串口操作是Java编程中一个相对特殊但重要的领域,主要涉及到硬件通信和设备交互。在实际应用中,比如工业自动化、物联网设备控制等场景,Java串口编程扮演着关键角色。标题提到的问题是关于数据传输时遇到的一个...

    JAVA类加载机制与动态代理

    1. **当遇到`new`、`getstatic`、`putstatic`或`invokestatic`这四条字节码指令时**,例如使用`new`关键字实例化对象、读取或设置一个类的静态字段(被`static`关键字修饰)、以及调用一个类的静态方法时。...

    Java虚拟机类装载:原理、实现与应用

    另一个例子是Java的反射API,它利用类装载机制在运行时动态访问和操作类的属性和方法。 总的来说,理解Java虚拟机的类装载机制对于深入掌握Java应用程序的运行机制至关重要。通过自定义ClassLoader,开发者可以实现...

    Md5加密java

    在这个例子中,我们首先通过`getInstance("MD5")`获取一个MD5的MessageDigest实例。然后使用`update()`方法更新待加密的数据,接着调用`digest()`获取计算后的哈希值。最后,我们将得到的字节数组转换为16进制字符串...

    java调用MD5加密方式计算摘要值(有界面)

    以下是一个简单的示例,展示了如何使用Java调用MD5加密来计算一个字符串的摘要值: ```java import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Example { ...

    MD5_java.rar_MD5 JAVA_java md5_md5_md5算法

    在这个例子中,`getMD5`方法接收一个字符串,使用`MessageDigest.getInstance("MD5")`创建一个MD5实例,然后对输入字符串的字节进行哈希处理。得到的结果是一个字节数组,接着通过`String.format("%02x", 0xFF & b)`...

    用java实现的md5加密与例子

    MD5(Message-Digest Algorithm 5)是一种...总的来说,Java中的MD5加密是一个简单但重要的概念,对于理解和实现数据安全的初级阶段至关重要。然而,随着安全需求的提高,开发者应当考虑使用更先进的加密算法和实践。

Global site tag (gtag.js) - Google Analytics