JAVA反序列化的简单探究

本文主要是探究,在反序列化过程中是怎么调用到readObject、readResolve、readExternal方法的问题

新建一个需要被序列化的类ObjectA,写入readResolve和readObject方法:

package com.yy.serialize.readResolve;

import java.io.IOException;
import java.io.Serializable; public class ObjectA implements Serializable {
private ObjectA() {
} private static final ObjectA objectA = new ObjectA(); public static ObjectA getInstance() {
return objectA;
}
private Object readResolve() {
System.out.println("执行了readResolve方法");
return objectA;
} private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
//执行默认的readObject()方法
in.defaultReadObject();
System.out.println("执行了readObject方法");
}
}

另一个类ObjectB则写入了readExternal方法:

package com.yy.serialize.readResolve;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput; public class ObjectB implements Externalizable {
@Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("执行了writeExternal");
} @Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("执行了readExternal");
}
}

测试类:

package com.yy.serialize.readResolve;

import java.io.*;

public class SerializeDemo {
public static void main(String[] args) throws Exception {
ObjectA objectA = ObjectA.getInstance();
ObjectB objectB = new ObjectB(); // 序列化
FileOutputStream fos = new FileOutputStream("a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(objectA);
oos.flush(); // 反序列化
FileInputStream fis = new FileInputStream("a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
ois.readObject(); }
}

运行测试类生成a.txt文件后,可以使用SerializationDumper查看字节流的数据:

这里有两个关键的标识

TC_OBJECT:标记后面的数据为Object对象

TC_CLASSDESC:类描述符标识,表示一个类中的所有信息

    TC_CLASSDESC - 0x72
className
Length - 36 - 0x00 24
Value - com.yy.serialize.readResolve.ObjectA - 0x636f6d2e79792e73657269616c697a652e726561645265736f6c76652e4f626a65637441
serialVersionUID - 0xee 44 c6 e6 0d b3 64 b5
newHandle 0x00 7e 00 00
classDescFlags - 0x02 - SC_SERIALIZABLE
fieldCount - 0 - 0x00 00
classAnnotations
TC_ENDBLOCKDATA - 0x78
superClassDesc
TC_NULL - 0x70

调用分析

ois.readObject下个断点

进入ObjectInputStream#readObject方法,看到其调用了readObject0

跟进readObject0,在此函数中,根据了tc值来进行switch,此时的tc值为TC_OBJECT,也就是0x73十进制数115

case TC_OBJECT中,调用了readOrdinaryObject

跟进readOrdinaryObject中,发现调用了readClassDesc方法,并把值赋给了desc

跟进readClassDesc,此方法用来分发处理字节流中TC_CLASSDESC的方法,用switch来选择需要处理的方法

tc的值就是TC_CLASSDESC的值0x72,转成10进制就是114,然后进入switch判断后转到case TC_CLASSDESC:

跟进readNonProxyDesc方法,调用了resolveClass方法后,把值赋给了cl

继续跟进resolveClass后,发现使用了Class.forName来创建了ObjectA对象,然后把创建的对象进行return返回

回到readNonProxyDesc,此时cl值变成了ObjectA对象,然后把cl对象传入了initNonProxy,并且赋值给了desc

最后readNonProxyDesc方法返回了desc的值

返回的desc的值赋给了调用处readClassDesc的descriptor,然后又进行了返回

最后回到了readOrdinaryObject方法中

在这里先总结下这几个方法分别做了什么操作

总结下上面的流程顺序为:

readOrdinaryObject -》 readClassDesc -》 readNonProxyDesc -》 readResolve方法

readClassDesc :分发用于处理字节流中TC_CLASSDESC的方法,用switch来选择需要处理的方法

readNonProxyDesc :真正用来处理字节流中的TC_CLASSDESC方法,会调用resolveClass进行创建反序列化的对象

resolveClass:是用Class.forName来创建ObjectA对象的地方,在这里可以做一个检查校验,用于反序列化拦截。weblogic中补丁拦截就是在此进行的

到这里三个方法都讲了用途后,还剩最后一个readOrdinaryObject 了

readOrdinaryObject

这里的readOrdinaryObject就是真正操作调用序列化类中,readObject、readResolve、readExternal方法的地方

接着上面debug,拿到了desc的值后往下走,做了一个判断desc.isExternalizable,如果序列化的接口是Externalizable类型,就进入readExternalData,否则进入readSerialData

此处的ObjectA对象接口类型是Serializable,所以进入了readSerialData方法

最后readSerialData方法中用了反射进行调用反序列化对象的readObject方法

回到readOrdinaryObject,接下来就是调用readResolve方法的地方了

用if进行判断,为true则用反射调用反序列化对象的readResolve方法

引用一张xz上师傅文章的流程图:

https://xz.aliyun.com/t/8443#toc-2

总结

方法调用的流程顺序:

readOrdinaryObject -》 readClassDesc -》 readNonProxyDesc -》 readResolve方法

readClassDesc :分发用于处理字节流中TC_CLASSDESC的方法,用switch来选择需要处理的方法

readNonProxyDesc :真正用来处理字节流中的TC_CLASSDESC方法,会调用resolveClass进行创建反序列化的对象

resolveClass:是用Class.forName来创建ObjectA对象的地方,在这里可以做一个检查校验,用于反序列化拦截。weblogic中补丁拦截就是在此进行的

readOrdinaryObject:用于调用序列化类中,readObject、readResolve、readExternal的方法

JAVA反序列化的简单探究的更多相关文章

  1. Java反序列化漏洞通用利用分析

    原文:http://blog.chaitin.com/2015-11-11_java_unserialize_rce/ 博主也是JAVA的,也研究安全,所以认为这个漏洞非常严重.长亭科技分析的非常细致 ...

  2. Java反序列化漏洞分析

    相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...

  3. Java反序列化漏洞实现

    一.说明 以前去面试被问反序列化的原理只是笼统地答在参数中注入一些代码当其反序列化时被执行,其实“一些代码”是什么代码“反序列化”时为什么就会被执行并不懂:反来在运营商做乙方经常会因为java反反序列 ...

  4. 关于metaspolit中进行JAVA反序列化渗透RMI的原理分析

    一.背景: 这里需要对java反序列化有点了解,在这里得推广下自己的博客嘛,虽然写的不好,广告还是要做的.原谅我: 1.java反序列化漏洞原理研习 2.java反序列化漏洞的检测 二.攻击手法简介 ...

  5. Java反序列化漏洞的挖掘、攻击与防御

    一.Java反序列化漏洞的挖掘 1.黑盒流量分析: 在Java反序列化传送的包中,一般有两种传送方式,在TCP报文中,一般二进制流方式传输,在HTTP报文中,则大多以base64传输.因而在流量中有一 ...

  6. Java IO流简单使用

    Java IO流简单使用 也许是以前IO方面接触的比较少,我对于读和写的概念老是混淆. 趁着现在实习比较闲小结一下,我个人理解读和写都是针对程序,分别就是程序的输入和输出,或者叫读入写出. Java ...

  7. Lib之过?Java反序列化漏洞通用利用分析

    转http://blog.chaitin.com/ 1 背景 2 Java反序列化漏洞简介 3 利用Apache Commons Collections实现远程代码执行 4 漏洞利用实例 4.1 利用 ...

  8. 通过JBoss反序列化(CVE-2017-12149)浅谈Java反序列化漏洞

    前段时间学校学习J2EE,用到了jboss,顺便看了下jboss的反序列化,再浅谈下反序列化漏洞. Java序列化,简而言之就是把java对象转化为字节序列的过程.而反序列话则是再把字节序列恢复为ja ...

  9. 学习笔记 | java反序列化漏洞分析

    java反序列化漏洞是与java相关的漏洞中最常见的一种,也是网络安全工作者关注的重点.在cve中搜索关键字serialized共有174条记录,其中83条与java有关:搜索deserialized ...

随机推荐

  1. 自学vue第二天,从入门到放弃(生命周期的理解)

    生命周期的理解 beforeCreate 创建前 数据还没有监听,没有绑定到vue对象实例,同时也没有挂载对象 没有数据也没有方法 created 在创建后 数据和方法已经 data数据已经绑定好了 ...

  2. 812考试总结(NOIP模拟37)[数列·数对·最小距离·真相]

    前言 考得挺憋屈的... 先是搞了两个半小时的 T1 后来发现假了,又没多想跳了.. 然后一看 T2 这不是队长快跑嘛... 先是根据自己的想法打了一遍(考完之后发现是对的..) 然后回想了一下之前的 ...

  3. Rancher v1.6.29 Docker单节点部署

    前言: Docker镜像中心,有两个版本的rancher(1.X),镜像名称为:rancher/server,而rancher(2.X)的镜像名称是rancher/rancher 去daocloud官 ...

  4. 【笔记】sklearn中的SVM以及使用多项式特征以及核函数

    sklearn中的SVM以及使用多项式特征以及核函数 sklearn中的SVM的使用 SVM的理论部分 需要注意的是,使用SVM算法,和KNN算法一样,都是需要做数据标准化的处理才可以,因为不同尺度的 ...

  5. 生成二维码项目pom.xml中QRCode依赖报错

    pom.xml报错如下: 解决方法: 1.将QRCode.jar包下载到E盘下 网盘下载地址: 链接:https://pan.baidu.com/s/1sY1NK5ekCkNH0uqraZMnKw 提 ...

  6. C#的生产者和消费者 实例

    class Program { //写线程将数据写入myData static int myData = 100; //读写次数 const int readWriteCount = 20; //fa ...

  7. uwp 的】listView 选择

    xml 代码 ---------------------------------------------------------- <Page x:Class="ContentCont ...

  8. Java finally语句到底是在return之前还是之后执行

    看过网上关于Java中异常捕获机制try-catch-finally块中的finally语句是不是一定会被执行的讨论也有很多. 首先明确一点,下面两种情况finally肯定是不执行的: 1). ret ...

  9. servlet初识servletConfig

    package day09; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; ...

  10. Node.js & Kubernetes Graceful Shutdown

    k8s-graceful-shutdown:该库提供了使用 Kubernetes 实现 Graceful Shutdown(优雅退出) Node.js App 的资源. 问题描述 在 kubernet ...