Java字节码校验

2018-04-12  本文已影响0人  0x70e8

记录一下修改class文件以及使用命令行执行class文件

1. 编写代码

在包jdk.test.classLoader下创建类VerifyTest,对应磁盘目录是D://workspace/Test/jdk.test.classloader

package jdk.test.classLoader;

public class VerifyTest {
    static int fun() {

        int m, n;
        m = 1;
        n = 2;
        return m + n;
    }

    public static void main(String[] args) {
        System.out.println(fun());
    }
}

2. 编译

javac VerifyTest.java;

3.反编译看字节码

$ javap -c VerifyTest.class
Compiled from "VerifyTest.java"
public class jdk.test.classLoader.VerifyTest {
  public jdk.test.classLoader.VerifyTest();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  static int fun();
    Code:
       0: iconst_1
       1: istore_0
       2: iconst_2
       3: istore_1
       4: iload_0
       5: iload_1
       6: iadd
       7: ireturn

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: invokestatic  #27                 // Method fun:()I
       6: invokevirtual #29                 // Method java/io/PrintStream.println:(I)V
       9: return
}

把方法fun的助记符的字节码(16进制找到)

  static int fun();
    Code:
       0: iconst_1  04
       1: istore_0  3B
       2: iconst_2  05  
       3: istore_1  3C
       4: iload_0   1A
       5: iload_1   1B
       6: iadd      60
       7: ireturn   AC

修改字节码文件

把3C改成3B,这样第一个局部变量就被初始化两次,而第二个变量没有被初始化(这是虚拟机不接受的)
再反编译一下:

$ javap -c VerifyTest.class
Compiled from "VerifyTest.java"
public class jdk.test.classLoader.VerifyTest {
  public jdk.test.classLoader.VerifyTest();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  static int fun();
    Code:
       0: iconst_1
       1: istore_0
       2: iconst_2
       3: istore_0   //此处变了
       4: iload_0
       5: iload_1
       6: iadd
       7: ireturn

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: invokestatic  #27                 // Method fun:()I
       6: invokevirtual #29                 // Method java/io/PrintStream.println:(I)V
       9: return
}


执行

到包的根目录下执行

$ pwd
/d/workspace/Test/bin
$ java -classpath . jdk.test.classLoader.VerifyTest
java.lang.VerifyError: Bad local variable type
Exception Details:
  Location:
    jdk/test/classLoader/VerifyTest.fun()I @5: iload_1
  Reason:
    Type top (current frame, locals[1]) is not assignable to integer
  Current Frame:
    bci: @5
    flags: { }
    locals: { integer }
    stack: { integer }
  Bytecode:
    0x0000000: 043b 053b 1a1b 60ac

        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
        at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
        at java.lang.Class.getMethod0(Class.java:3018)
        at java.lang.Class.getMethod(Class.java:1784)
        at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
        at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main"

不验证:

$ java -noverify jdk.test.classLoader.VerifyTest
2
上一篇 下一篇

猜你喜欢

热点阅读