rmi中采用的局部过滤
我们之前是调试过rmi的各种利用的,但是这里补充一个新的点(其实应该也能发现,有些地方比如SAC的确正是如此):rmi中的registerImpl也就是注册中心并不是必须的,参考:深入理解rmi原理 - 简书 (jianshu.com)
RMIRegistry 是必须的吗?
No,RMIRegistry 起到的作用只是为了方便client获取到stub对象,如果还有其他的方法让client拿到stub就不需要RMIRegistry 了,因为client一旦拿到了stub就不需要RMIRegistry 了
作者:春天里的布谷鸟
链接:https://www.jianshu.com/p/2c78554a3f36
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
我们熟知的bind, lookup, rebind 等等方法实际上是在操作registerImpl
可以看到有四个实现的接口
bind
bind,unbind
list
这个成员变量到底是什么呢
客户端调用的 bind
, lookup
,list
等操作,实际上是操作 RegistryImpl
的 bindings
这个 Hashtable
。
不信的话可以复现一下,小调一波
老样子我们调试一下,在这里lookup断点
一路进去,见到Lookup就进去
然后到registerImpl_stub这里果然就进不去了,验证刚刚的说法,实际上那么多个lookup要操作的就只是registerImpl_stub
然后可以看到下面就是典型的readObject啥的,原生反序列化
这里我们之所以称RegistryImpl
是一个特殊的对象,是因为 `RegistryImpl
导出过程中生成 Target
对象是一个“定制”的 Target
对象,具体体现在:
1.这个Target 中 id 的 objNum 是固定的,为 ObjID.REGISTRY_ID ,也就是 0 。
2.这个Target 中 disp 是 filter 为 RegisryImpl::RegistryFilter ,skel 为 RegsitryImpl_skel 的 UnicastServerRef 对象。
3.这个Target 中 stub 为 RegistryImpl_stub。
这里我也想调试的,但是没办法
装插件也没用:(52条消息) IDEA 如何进入.class文件上打的的debug断点_idea 怎么断点到class文件里面去_jiuqijack的博客-CSDN博客
这个地方不是在lookup触发的。
找了半天,原来是在创建这个对象的时候触发的
从setup进去,
可以看到,这里的id的objNum= 0
下面的 impl 是 这个RegistryImpl对象
disp的filter不为null (其实是RegistryImpl::RegistryFilter),skel为RegistryImpl_skel的UnicastServerRef
stub为registryImpl_stub
对比普通对象导出的过程中生成的Target, (以下是网图)
具体导出过程:
首先LocateRegistry.createRegistry
强制进去
进去,调用了一些静态方法后,来到这个地方
注意到LiveRef这个地方的id是0
还有一处细节,我上面用的是jdk8u313,就是没有JEP290的,而你看下面
这个是有JEP290限制的
所以整份代码读下来就是
new RegistryImpl(port)
中会 new
一个UnicastServerRef
对象,将 RegistryImpl
的 id
(OBJID.REGISTRY_ID
,也就是 0 ) 存入到 LiveRef
对象,随后 LiveRef
对象赋值到 UnicastServerRef
对象中的 ref
字段,并且将 RegsitryImpl::registryFilter
赋值给这个 UnicastServerRef
对象的 filter
字段:
随后我们单步进入this.setup(new UnicastServerRef(var2, RegistryImpl::registryFilter));
循规蹈矩的赋值
注意filter
出来后,进入setup,可以看到马上exportObject
然后就又来到刚刚前面分析过的地方
1.这个Target 中 id 的 objNum 是固定的,为 ObjID.REGISTRY_ID ,也就是 0 。
2.这个Target 中 disp 是 filter 为 RegisryImpl::RegistryFilter ,skel 为 RegsitryImpl_skel 的 UnicastServerRef 对象。
3.这个Target 中 stub 为 RegistryImpl_stub。
exportObject
会调用 TCPEndpoint.export
再跟进
这里调用的就是前面的exportObject
服务端处理请求过程
这里不调了,调了一晚上调了个寂寞,根本找不到! 带带我5555555
处理请求是在 Transport#serviceCall
,首先从输入流中读取 id
, 匹配到 RegistryImpl
对象对应的 Target
。
随后调用 UnicastServerRef.dispatch
:
在 UnicastServerRef#dispatch
中,由于 UnicastServerRef.skel
不为 null
,所以会调用 UnicastServerRef#oldDispatch
方法:
oldDispatch
中会先调用 unmarshalCustomCallData(in)
方法,再调用 RegistryImpl_skel.dispatch
方法。
unmarshalCustomCallData
方法中会进行判断,如果 UnicastServerRef.filter
不为 null
,就会设置 ConnectionInputStream
的 serialFilter
字段值为 UnicastServerRef.filter
(设置单个 ObjectInputStream
的 serialFilter
属性,局部过滤的体现):
再看 RegistryImpl_skel.dispatch
:
我们以 bind
为例来讲解: