1.简介
Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。接口的两种常见实现方式是:最初使用JRMP(Java Remote Message Protocol,Java远程消息交换协议)实现;此外还可以用与CORBA兼容的方法实现。RMI一般指的是编程接口,也有时候同时包括JRMP和API(应用程序编程接口),而RMI-IIOP则一般指RMI接口接管绝大部分的功能,以支持CORBA的实现。最初的RMI API设计为通用地支持不同形式的接口实现。后来,CORBA增加了传值(pass by value)功能,以实现RMI接口。然而RMI-IIOP和JRMP实现的接口并不完全一致。
2原理:
架构图:

RMI底层通讯采用了Stub(运行在客户端)和Skeleton(运行在服务端)机制,RMI调用远程方法的大致如下:
RMI客户端在调用远程方法时会先创建Stub(sun.rmi.registry.RegistryImpl_Stub)。Stub会将Remote对象传递给远程引用层(java.rmi.server.RemoteRef)并创建java.rmi.server.RemoteCall(远程调用)对象。RemoteCall序列化RMI服务名称、Remote对象。RMI客户端的远程引用层传输RemoteCall序列化后的请求信息通过Socket连接的方式传输到RMI服务端的远程引用层。RMI服务端的远程引用层(sun.rmi.server.UnicastServerRef)收到请求会请求传递给Skeleton(sun.rmi.registry.RegistryImpl_Skel#dispatch)。Skeleton调用RemoteCall反序列化RMI客户端传过来的序列化。Skeleton处理客户端请求:bind、list、lookup、rebind、unbind,如果是lookup则查找RMI服务名绑定的接口对象,序列化该对象并通过RemoteCall传输到客户端。RMI客户端反序列化服务端结果,获取远程对象的引用。RMI客户端调用远程方法,RMI服务端反射调用RMI服务实现类的对应方法并序列化执行结果返回给客户端。RMI客户端反序列化RMI远程方法调用结果。
参考:https://www.javasec.org/javase/RMI/
3代码示例
服务端
1 | package com.rmi; |
上述代码中,在8989端口起了RMI服务,以键值对的形式存储了RMI_PATH和rmiInterface的对应关系,也就是rmi://127.0.0.1:8989/hello对应一个ServicetestImpl类实例,然后通过Naming.rebind(RMI_NAME, rmiInterface)绑定对应关系。再来看Servicetest.java
1 | package com.rmi; |
定义了RMIInterface接口,继承自Remote,然后定义了一个test()方法作为接口。注意需要抛出RemoteException异常。继续看实现真正功能的类ServicetestImpl.java
1 | package com.rmi; |
继承自UnicastRemoteObject类,并且实现之前定义的Servicetest接口的test()方法。UnicastRemoteObject类提供了很多支持RMI的方法,具体来说,这些方法可以通过JRMP协议导出一个远程对象的引用,并通过动态代理构建一个可以和远程对象交互的Stub对象。现在就定义好了Server端,来看Client
1 | package com.rmi; |
参考:https://su18.org/post/rmi-attack/#2-%E6%94%BB%E5%87%BB-registry-%E7%AB%AF
https://paper.seebug.org/1091/#java-rmi_2
https://xz.aliyun.com/t/7079?time__1311=n4%2BxnD0Dy7itGQNKGNnmAzti%3DDkW3DB7in1oD
https://xz.aliyun.com/t/7264?time__1311=n4%2BxnD0Dy7G%3DBxGqGNnmADR7DgDfErrx3%2BBbD#toc-0
https://y4er.com/posts/java-rmi/
https://www.javasec.org/javase/RMI/
http://www.mi1k7ea.com/2019/09/01/Java-RMI%E5%8E%9F%E7%90%86%E4%B8%8E%E4%BD%BF%E7%94%A8/
https://www.cnblogs.com/nice0e3/p/14280278.html
https://www.bilibili.com/video/BV1L3411a7ax?p=5&vd_source=82398f68c82cb90e0d9aa4fea90e36a0
https://townmacro.cn/2022/04/18/java-%E5%AE%89%E5%85%A8-rmi%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/
https://su18.org/post/rmi-attack/#%E5%9B%9B-%E6%94%BB%E5%87%BB-rmi
https://xz.aliyun.com/t/7079?time__1311=n4%2BxnD0Dy7itGQNKGNnmAzKDtf%3D4AKDkWe6YeD
https://paper.seebug.org/1091/#java-rmi_2
https://forum.butian.net/share/2278
https://xz.aliyun.com/t/7264?time__1311=n4%2BxnD0Dy7G%3DBxGqGNnmADR7DgDfErrx3%2BBbD#toc-2
https://townmacro.cn/2022/04/18/java-%E5%AE%89%E5%85%A8-rmi%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/