一,超猪聊技术----jdk对象序列化协议

来源:互联网 发布:阿里云防cc攻击 编辑:程序博客网 时间:2024/06/08 13:51

最近碰到一个项目,需要使用nodejs反序列化存储在redis中的session对象(jdk序列化),花了点时间研究了下jdk序列化协议。同时感谢fengmk2大神提供的开源项目java.io

参考资料

jdk序列化介绍: https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html


1. 基本介绍

       java中的对象序列化操作类可以ObjectOutputStream(写入),  ObjectInputStream(读取),首先我们看看如何操作将对象序列化后写入文件和从文件中读取。

      

      1.1 将str对象写入文件

     String str = "str";     FileOutputStream fileOutputStream = new FileOutputStream("d://string.bin");     ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);     objectOutputStream.writeObject(str);

          string.bin写入结果如下, (可以使用editplus)


     00000000 AC ED 00 05 74 00 03 73 74 72                     ....t..str           

       1.2 从文件中读取str对象

     FileInputStream fileInputStream = new FileInputStream("d://string.bin");     ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);     Object str = objectInputStream.readObject();             System.out.println(str);

          输出结果


     str

2. Str对象协议解析

        AC ED:   任何对象序列化后都是以这两个字节的"魔化数字"开始

        00 05:   当前对象序列化格式的版本号

        74: TC_STRING 表示string字符串的开始

        03: 该string字符串的长度

        73 74 72:  该string的值“str”

    

String对象的序列化还是比较简单的,接下来介绍复杂对象的序列化协议


3. Date对象协议解析

      3.1 Date对象序列化结构(写入文件方式和1.1一致, 此处就不再重复)

    00000000 AC ED 00 05 73 72 00 0E 6A 61 76 61 2E 75 74 69   ....sr..java.uti    00000010 6C 2E 44 61 74 65 68 6A 81 01 4B 59 74 19 03 00   l.Datehj..KYt...    00000020 00 78 70 77 08 00 00 01 4B 6D 65 DB B4 78         .xpw....Kme..x

        AC ED: 两个字节的"魔化数字"

        00 05: 当前对象序列化格式的版本号

        73: TC_OBJECT 表示对象开始

        72: TC_CLASSDESC Class定义开始

        00 0E: 类名(字符串)的长度

        6A 61 76 61 2E 75 74 69 6C 2E 44 61 74 65: java.util.Date字符串(ASCII)

        68 6A 81 01 4B 59 74 19: 8个字节的指纹

        03: 1个字节长的标志(见附录介绍)  

        00 00: 2个字节长的数据或描述符的计数值

        78: 结束标志

        70: 没有超类

        77: BlOCKDATA的开始标志

        08: 数据字节长度

        00 00 01 4B 6D 65 DB B4: 8个字节的time的值(1970年1月1日到该时间的毫秒数)

        78: ENDBLOCKDATA 结束标志

       

      3.2 Date对象的writeObject, readObjct方法

        Date的类定义的标志显示包含SC_WRITE_METHOD(计算方式见附录), 表示类包含writeObject, readObject方法,数据读取写入都会依照该两个方法调用  


    /**     * Save the state of this object to a stream (i.e., serialize it).     *     * @serialData The value returned by <code>getTime()</code>     *             is emitted (long).  This represents the offset from     *             January 1, 1970, 00:00:00 GMT in milliseconds.     */    private void writeObject(ObjectOutputStream s)         throws IOException    {        s.writeLong(getTimeImpl());    }    /**     * Reconstitute this object from a stream (i.e., deserialize it).     */    private void readObject(ObjectInputStream s)         throws IOException, ClassNotFoundException    {        fastTime = s.readLong();    }


附录:

       标志位

    final static byte SC_WRITE_METHOD = 0x01; //if SC_SERIALIZABLE    final static byte SC_BLOCK_DATA = 0x08;    //if SC_EXTERNALIZABLE    final static byte SC_SERIALIZABLE = 0x02;    final static byte SC_EXTERNALIZABLE = 0x04;    final static byte SC_ENUM = 0x10;
       

        SC_WRITE_METHOD: Class定义包含readObject, writeObject方法

       标志位计算方式

         例:

        标志为0x03, 判断是否包含SC_WRITE_METHOD

        标志0x03, 转换为二进制

    0000 0011

        SC_WRITE_METHOD 0x01, 转换为二进制

    0000 0001
        做&运算结果如下
    0000 0001
        该结果大于0, 则包含SC_WRITE_METHOD

      终端符号和常量

    final static short STREAM_MAGIC = (short)0xaced;    final static short STREAM_VERSION = 5;    final static byte TC_NULL = (byte)0x70;    final static byte TC_REFERENCE = (byte)0x71;    final static byte TC_CLASSDESC = (byte)0x72;    final static byte TC_OBJECT = (byte)0x73;    final static byte TC_STRING = (byte)0x74;    final static byte TC_ARRAY = (byte)0x75;    final static byte TC_CLASS = (byte)0x76;    final static byte TC_BLOCKDATA = (byte)0x77;    final static byte TC_ENDBLOCKDATA = (byte)0x78;    final static byte TC_RESET = (byte)0x79;    final static byte TC_BLOCKDATALONG = (byte)0x7A;    final static byte TC_EXCEPTION = (byte)0x7B;    final static byte TC_LONGSTRING = (byte) 0x7C;    final static byte TC_PROXYCLASSDESC = (byte) 0x7D;    final static byte TC_ENUM = (byte) 0x7E;    final static int baseWireHandle = 0x7E0000;




0 0