EasyHook,.NET Remoting客户端和服务器之间的共享接口?

IPC客户端和IPC服务器如何调用共享远程处理接口(inheritanceMarshalByRefObject的类)进行通信,而不必将接口类放在注入应用程序中? 例如,如果我将接口类放入注入的库项目中并注入到我的目标进程中,那么我的注入应用程序就无法引用该接口。

编辑:我已经回答了下面的问题。

从EasyHook Commit 66751 (与EasyHook 2.7 alpha绑定)开始,似乎无法在客户端( 启动注入DLL的进程)和服务器( 注入的进程运行你的服务器)中获取远程处理接口的实例注入DLL)。

我的意思是什么?

好吧,在FileMon和ProcessMonitor示例中,请注意共享远程处理接口( FileMonInterface ,嵌入在Program.cs ,对于Filemon ,以及DemoInterface ,在其自己的文件中,对于ProcessMonitor )是如何放置在注入程序集中的。 FileMonInterface位于FileMon项目中。 DemoInterface位于ProcessMonitor项目中。

为什么不是另一轮呢? 为什么不将FileMonInterface放在项目FileMonInject中,并将DemoInterface放在DemoInterface中? 因为调用应用程序(FileMon和ProcessMonitor)将无法再访问这些接口。

原因是因为EasyHook内部使用:

 RemotingConfiguration.RegisterWellKnownServiceType( typeof(TRemoteObject), ChannelName, InObjectMode); 

此远程调用允许客户端调用您的(服务器)接口,但服务器本身(您,应用程序)无法调用它。

解决方案

相反,使用:

 // Get the instance by simply calling `new RemotingInterface()` beforehand somewhere RemotingServices.Marshal(instanceOfYourRemotingInterfaceHere, ChannelName); 

我所做的是为EasyHook的RemoteHook.IpcCreateServer()添加一个重载,以接受我做.NET远程处理的新“方式”。

这很难看,但它有效:

代码

使用以下代码替换整个IpcCreateServer方法(从大括号到大括号)。 这里显示了两种方法。 一个是更详细的过载。 第二种是调用我们超载的“原始”方法。

 public static IpcServerChannel IpcCreateServer( ref String RefChannelName, WellKnownObjectMode InObjectMode, TRemoteObject ipcInterface, String ipcUri, bool useNewMethod, params WellKnownSidType[] InAllowedClientSIDs) where TRemoteObject : MarshalByRefObject { String ChannelName = RefChannelName ?? GenerateName(); /////////////////////////////////////////////////////////////////// // create security descriptor for IpcChannel... System.Collections.IDictionary Properties = new System.Collections.Hashtable(); Properties["name"] = ChannelName; Properties["portName"] = ChannelName; DiscretionaryAcl DACL = new DiscretionaryAcl(false, false, 1); if (InAllowedClientSIDs.Length == 0) { if (RefChannelName != null) throw new System.Security.HostProtectionException("If no random channel name is being used, you shall specify all allowed SIDs."); // allow access from all users... Channel is protected by random path name! DACL.AddAccess( AccessControlType.Allow, new SecurityIdentifier( WellKnownSidType.WorldSid, null), -1, InheritanceFlags.None, PropagationFlags.None); } else { for (int i = 0; i < InAllowedClientSIDs.Length; i++) { DACL.AddAccess( AccessControlType.Allow, new SecurityIdentifier( InAllowedClientSIDs[i], null), -1, InheritanceFlags.None, PropagationFlags.None); } } CommonSecurityDescriptor SecDescr = new CommonSecurityDescriptor(false, false, ControlFlags.GroupDefaulted | ControlFlags.OwnerDefaulted | ControlFlags.DiscretionaryAclPresent, null, null, null, DACL); ////////////////////////////////////////////////////////// // create IpcChannel... BinaryServerFormatterSinkProvider BinaryProv = new BinaryServerFormatterSinkProvider(); BinaryProv.TypeFilterLevel = TypeFilterLevel.Full; IpcServerChannel Result = new IpcServerChannel(Properties, BinaryProv, SecDescr); if (!useNewMethod) { ChannelServices.RegisterChannel(Result, false); RemotingConfiguration.RegisterWellKnownServiceType( typeof(TRemoteObject), ChannelName, InObjectMode); } else { ChannelServices.RegisterChannel(Result, false); ObjRef refGreeter = RemotingServices.Marshal(ipcInterface, ipcUri); } RefChannelName = ChannelName; return Result; } ///  /// Creates a globally reachable, managed IPC-Port. ///  ///  /// Because it is something tricky to get a port working for any constellation of /// target processes, I decided to write a proper wrapper method. Just keep the returned ///  alive, by adding it to a global list or static variable, /// as long as you want to have the IPC port open. ///  ///  /// A class derived from  which provides the /// method implementations this server should expose. ///  ///  ///  if you want to handle each call in an new /// object instance,  otherwise. The latter will implicitly /// allow you to use "static" remote variables. ///  ///  /// Either null to let the method generate a random channel name to be passed to ///  or a predefined one. If you pass a value unequal to /// null, you shall also specify all SIDs that are allowed to connect to your channel! ///  ///  /// If no SID is specified, all authenticated users will be allowed to access the server /// channel by default. You must specify an SID if  is unequal to null. ///  ///  /// An  that shall be keept alive until the server is not needed anymore. ///  ///  /// If a predefined channel name is being used, you are required to specify a list of well known SIDs /// which are allowed to access the newly created server. ///  ///  /// The given channel name is already in use. ///  public static IpcServerChannel IpcCreateServer( ref String RefChannelName, WellKnownObjectMode InObjectMode, params WellKnownSidType[] InAllowedClientSIDs) where TRemoteObject : MarshalByRefObject { return IpcCreateServer(ref RefChannelName, InObjectMode, null, null, false, InAllowedClientSIDs); } 

而已。 这就是你需要改变的全部。 您不必更改IpcCreateClient()。

使用代码

以下是使用新重载方法的方法:

说你有

 public class IpcInterface : MarshalByRefObject { /* ... */ } 

作为您的共享远程处理界面。

创建它的新实例,并存储其引用。 您将使用它与您的客户沟通。

 var myIpcInterface = new IpcInterface(); // Keep this reference to communicate! 

以下是您之前创建该远程通道的方法:

  ipcServer = RemoteHooking.IpcCreateServer(ref IpcChannelName, WellKnownObjectMode.Singleton, WellKnownSidType.WorldSid); 

以下是如何创建远程通道的方法:

  ipcServer = RemoteHooking.IpcCreateServer(ref IpcChannelName, WellKnownObjectMode.Singleton, myIpcInterface, IpcChannelName, true, WellKnownSidType.WorldSid); 

别忘了……

我从这个StackOverflowpost中得到了这个解决方案。 请确保按照他的说法执行操作并覆盖InitializeLifetimeService以返回null:

 public override object InitializeLifetimeService() { // Live "forever" return null; } 

我认为这应该让客户端不会丢失远程接口。

用途

现在,您可以创建专门用于接口文件的库,而不是强制将远程处理接口文件放在与注入项目相同的目录中。

这个解决方案对于那些有.NET远程处理经验的人来说可能是常识,但我对此一无所知(可能在这篇文章中使用了“接口错误”这个词)。