65.9K
CodeProject 正在变化。 阅读更多。
Home

DCOM 传输

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.43/5 (3投票s)

2009年6月2日

CPOL

4分钟阅读

viewsIcon

32498

downloadIcon

421

你自己的 DCOM 传输

引言

DCOM 使用端口 #135 用于计算机上的所有进程,这很糟糕。WinXp SP2 非常彻底地关闭了这个常见的漏洞,这很好。但对开发人员来说却并非如此。是的,你可以让你的客户哭泣,但要配置策略。你甚至可以设法自动调整这些设置,就像一个真正的病毒一样。但仍然存在另一个大问题 - 你在局域网中。VPN 是让你的 DCOM 项目通过互联网工作**的唯一方法**。这非常丑陋。

让我们想想令人愉快的事情:试想一下,如果你可以在服务器端选择任何端口。只需在防火墙中允许此端口,仅此而已……试想一下,你可以在客户端通过代理。无需 VPN - 无需痛苦。试想一下,你正在控制你的整个 DCOM 流量 - 你可以压缩它,加密它,计算它,总而言之 - 只是管理它。

好消息是:我们可以给 DCOM 另一条轨道!

解决方案

IRpcChannelBuffer 是答案。COM 对象之间的进程内通信基于在好的情况下直接调用。在坏的情况下,即使在两个对象之间的一个进程中,也有另外两个对象在起作用 - 代理和存根。代理从调用端获取直接调用并将整个信息打包到一个缓冲区中,然后将其发送到存根。存根解包它并对被调用的对象进行直接调用。对于这种通信,代理和存根使用 IRpcChannelBuffer

总而言之,如果我们实现此接口并以某种方式将其传递给存根和代理 - 它们就开始使用你自己的通道进行交互。让我们看看主要的接口函数

首先:我们可以实现我们自己的传输

virtual HRESULT STDMETHODCALLTYPE SendReceive(RPCOLEMESSAGE *, ULONG *) = 0;

我们可以用任何可以想象的方式发送和接收这些数据。其次:我们甚至可以管理内存,并使我们的传输非常有效,避免无用的复制。

virtual HRESULT STDMETHODCALLTYPE GetBuffer(RPCOLEMESSAGE *, REFIID riid)  = 0; 
virtual HRESULT STDMETHODCALLTYPE FreeBuffer(RPCOLEMESSAGE *pMessage) = 0;

一个合理的问题 - 如何通过我们对接口的实现让代理和存根工作?让我们看看另外两个接口 IRpcProxyBuffer IRpcStubBuffer

IRpcProxyBuffer 只有两个方法

virtual HRESULT STDMETHODCALLTYPE Connect(IRpcChannelBuffer *) = 0;
virtual void STDMETHODCALLTYPE Disconnect(void) = 0;

这就是我们将代理连接到我们的通道的方式。IRpcStubBuffer 有多个方法,但只有一个有价值

virtual HRESULT STDMETHODCALLTYPE Invoke(RPCOLEMESSAGE*, IRpcChannelBuffer*)=0;

所以所有工作看起来像这样

  1. 将代理连接到你的 IRpcChannelBuffer 实现。
  2. 当它调用 SendReceive 时,将缓冲区传递给另一端。
  3. 在另一端,只需使用接收到的缓冲区调用 Invoke 即可。
  4. 将填充有输出数据的缓冲区发送回客户端。
  5. SendReceive 返回,并带有输出缓冲区。

另一个合理的问题:如何创建存根并将其连接到服务器端的对象,以及如何在客户端创建代理?这也很简单:GetPSFactory 是答案。

HRESULT GetPSFactory(REFIID riid, IPSFactoryBuffer ** ppProxyStubFactory);

此函数通过给定的 IID 创建工厂。工厂接口由两个非常有用的方法组成

virtual HRESULT STDMETHODCALLTYPE CreateProxy
	(IUnknown *pUnkOuter,REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateStub
	(REFIID riid,IUnknown *pUnkServer,IRpcStubBuffer **ppStub) = 0;

代理是将在你想要使用的远程对象中扮演角色的对象。因此,创建代理时,我们只需设置 IID 并获取接口本身和 IRpcProxyBuffer,该接口适用于连接到我们的 IRpcChannelBuffer。当我们调用所需接口的方法时,我们会收到对 SendReceive 的调用,并带有准备发送到另一端的缓冲区。在另一端,我们必须首先创建一个真实的对象,然后将存根连接到它。CreateStub 获取 IID 并为你提供 IRpcStubBuffer ,你可以将其连接到真实对象,调用

virtual HRESULT STDMETHODCALLTYPE Connect(IUnknown *pUnkServer) = 0;

太简单,不真实

是的,开始很容易。只拥有这些知识,你将得到什么?只有一个连接到服务器端对象的接口。对该接口的所有调用都将通过你的实现传递。这就是好的全部。但有坏消息

  1. 如果你的接口有一个使用另一个方法工作的接口 - DCOM 将其连接到端口 #135!
  2. CreateProxy 并不总能创建代理,尽管代理确实存在。
  3. 你无法使用异步调用。
  4. 你甚至无法通过这个代理存根对使用另一个接口 - 你需要为另一个接口重复整个过程。
  5. 还有许多其他事情,即使没有深入研究 DCOM 的内部世界,也无法解释…

附件

在 DCOMTransport.zip 中,你将找到一个结合了以上所有内容的源代码示例。此测试演示了如何在传输链中插入你自己的功能。在这种情况下,该功能是取消调用。

历史

  • 2009年5月25日:初始发布
© . All rights reserved.