2014-01-12 71 views
4

假设我在第三方dll中有一个私有的“实例”非静态bool方法。所有这些方法都会返回一个值。没有其他的。我将如何去截取对此方法的调用,更改它的IL OpCodes /方法体,或者将它重定向到一个额外的,重写的或派生的方法。C#拦截/更改/重定向方法

我不想反编译第三方DLL,手动更改源代码并重新编译它。 我也宁愿不将程序集保存到磁盘,因为这也涉及使用“重新编译的”程序集而不是原始程序集。

我基本上想要能够使用原始的dll - 没有替换或文件的变化。我只想做我上面提到的。

有什么办法可以解决这个问题吗?如果是这样,你可以详细说明或发布参考文献/教程/等。另外,我知道虚拟,重写和新修饰符,但请记住我:没有所述第三方DLL的来源,无法访问源代码,也不想用诸如dotPeek并重新编译。

谢谢!

编辑: 我忘了提及基础架构的其余部分: MainProgram加载ThirdPartyDLL。 MainProgram也加载MyPluginDLL。 我试图从MyPluginDLL中更改ThirdPartyDLL中的方法,以便在MainProgram调用所述方法时,它将调用更改的方法。我希望能够在不保存新程序集的情况下执行此操作,并使用新程序集重新启动MainProgram。实质上,我想在启动时或MainProgram运行时执行此操作。

+0

我敢打赌你正在寻找[Mono.Cecil](http://www.mono-project.com/Cecil)。 [教程在这里](http://stackoverflow.com/questions/1513319/mono-cecil-documentation-and-tutorials) – Measuring

+0

@Measuring,我知道我是。但我在哪里看?我只知道ReadAssembly和SaveAssembly。请记住,我不想保存和使用新的程序集。我想使用相同的程序集文件/ DLL,而不必保存更改后的文件。 – user3150838

+0

你是想拦截这个方法的所有调用,或者只是你对这个方法的调用? –

回答

4

下面是一个代码示例,用于使用Mono Cecil更改内存中的程序集并执行其中的方法。请注意,修改和保存组件非常缓慢。这应该在启动应用程序时完成。

class Program 
{ 
    static void Main(string[] args) 
    { 
     Assembly assembly; 
     using (MemoryStream assemblyStream = new MemoryStream(File.ReadAllBytes("TargetDLL.dll"))) 
     { 
      // 1. Get the reference to third-party method. 
      AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(assemblyStream); 
      TypeDefinition targetDLLType = assemblyDef.Modules[0].GetType("TargetDLL.Foo"); 
      MethodDefinition barMethod = targetDLLType.Methods[0]; 

      // 2. Let's see what Foo.Bar returns... 
      assembly = Assembly.Load(assemblyStream.ToArray()); 
      Console.WriteLine(CallMethod<int>(assembly.GetType("TargetDLL.Foo"), "Bar")); 

      // 3. Boot up the IL processor. 
      var processor = barMethod.Body.GetILProcessor(); 

      // 4 View the unmodified IL. 
      Console.WriteLine("Original code"); 
      PrintIL(processor); 

      // 5. Modify the code. 
      // 5.a Clear the method of all IL. 
      processor.Body.Instructions.Clear(); 

      // 5.b Inject our custom return value. 
      processor.Emit(OpCodes.Ldc_I4, 1337); 
      processor.Emit(OpCodes.Ret); 

      // 6. And how does it look now? 
      Console.WriteLine(); 
      Console.WriteLine("New code"); 
      PrintIL(processor); 

      // 7. Save it. 
      assemblyDef.Write(assemblyStream); 
      assembly = Assembly.Load(assemblyStream.ToArray()); 

      // 8. Result value. 
      Console.WriteLine(CallMethod<int>(assembly.GetType("TargetDLL.Foo"), "Bar")); 
     } 

     Console.WriteLine("END"); 
     Console.ReadKey(true); 
    } 

    static void PrintIL(ILProcessor processor) 
    { 
     foreach (var instruction in processor.Body.Instructions) 
     { 
      Console.WriteLine(instruction); 
     } 
    } 

    static T CallMethod<T>(Type type, string method) 
    { 
     return (T)type.InvokeMember("Bar", BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public, null, null, 
      null); 
    } 
} 

在同一目录中添加以下名为TargetDLL.dll的DLL。包含此代码:

namespace TargetDLL 
{ 
    public static class Foo 
    { 
     public static int Bar() 
     { 
      return 0; 
     } 
    } 
} 

编辑

我认为你的错误有Mono.Cecil能的版本做。我从master branch on GitHub使用9.5.0。下载ZIP文件并根据需要构建项目。

+0

我试过这个测量,但是我得到这个错误: http:// pastebin。com/xPXJgn6k – user3150838

+0

另外,请检查我在原始文章中所做的修改。希望它能帮助你理解 – user3150838

+0

另外,如果类和方法是非静态的,你的方法是否可以工作? – user3150838