这篇文章纯纯参考 FastJson与原生反序列化(二) 这个做的一些调试和学习,做一下总结,我脑子不好使,师傅没有讲细节,我来分析的再细节点。
一个简单的例子
直接用文章里的例子:
1 | package com.ctf.ezser.test; |
例子很简单奥,直接运行会报错说 autoType is not support
:
把 bd
前面的 “a” 换成 “c”:
代码执行成功了,这是为什么呢。
调试过程
直接在 BadAttributeValueExpException
的 readObject 下个断点:
会发现这里的 JSONArray
的 TemplateImpl
已经恢复了。怎么恢复的呢?
在反序列化恢复的时候存在一个东西:
这个东西翻译过来就是引用,进入到 readHandle 看看:
其实也不用仔细看,大概的意思就是如果类型是引用类型,那么就去 handles 里面找,如果找到的了就直接返回类。
然而 resolveClass 这个函数是在上面那个图里的 TC_OBJECT 里面的 readOrdinaryObject 里面调用的,说白了就是在反序列化的时候调用的,但是这个时候我们的 TemplatesImpl 这个类都已经出来了。所以自然就不需要调用到 JSONObject 的 resolveClass 了。
调试过程2
强行分个段,在 readHandle 这里下个断点,看看 JSONArray 里的那个 TemplatesImpl 是怎么恢复的:
这三张图是逆推的图,链子其实就是 BadAttributeValueExpException.readObject 的时候恢复 JSONArray,然后 JSONArray 里面恢复 TemplatesImpl(其实不是 JSONArray ,应该是 JSONObject 下的 SecureObjectInputStream),恢复的时候用的引用类型,直接从 handles 里面找,就不用到 JSONObject.SecureObjectInputStream 的 resolveClass 了。
分析引用类型
我们看看他是什么时候加进去的
进去 handles.lookupObject:
会发现它是获取的 entries 里的,看看 entries 是什么时候加进去的:
找到这个函数:java.io.ObjectInputStream.HandleTable#assign
看看调用栈,往上看看:
此处是 HashMap 的 readObject 在做反序列化恢复,恢复的就是 TemplatesImpl 这个类,这个时候当然是没有黑名单的。
一个总结
可能讲的有点乱,到此为止直接总结一下过程就好了:
现在一共是:
1 | HashMap 内有两个数据,这里的 -> 是包含关系 |
然后首先恢复HashMap,然后恢复第一个数据,第一个数据 键是b,值是 TemplatesImpl,恢复到第二个键 c 的时候再恢复 TemplatesImpl 时就不需要再readObject了,直接取就完事了。
也就是一个先后顺序的问题,如果把 字符串c 改成 字符串a 的话,这个时候就先恢复 BadAttribute 了,发现引用类型里找不到就会去调用 JSObject 的 resolveClass 恢复类了~