2014-01-12 4 views
4

Предположим, у меня есть частный, «экземпляр», нестатический метод bool в сторонней dll. Весь этот метод возвращает значение. Ничего больше. Как я могу перехватить вызовы этого метода, изменить его IL OpCodes/тело метода или перенаправить его на дополнительный, переопределенный или производный метод.C# Перехват/изменение/перенаправление метода

Я не хочу декомпилировать стороннюю dll, вручную изменить источник и перекомпилировать его. Я также предпочел бы не сохранять сборку на диск, так как это также предполагает использование «перекомпилированной» сборки вместо оригинала.

Я в основном хочу иметь возможность использовать исходную dll - никаких замен или изменений файлов. Я просто хочу сделать то, о чем я говорил выше.

Есть ли способ обойти это? Если да, можете ли вы разработать или опубликовать ссылки/учебники/и т. Д.

Кроме того, я знаю об виртуальных, переопределяющих и новых модификаторах, но помню, что я: не имею источника упомянутой сторонней DLL, не могу получить доступ к источнику, не хочу декомпилировать что-то вроде dotPeek и перекомпилировать.

Спасибо!

Редактировать: Я забыл упомянуть остальную инфраструктуру: MainProgram загружает ThirdPartyDLL. MainProgram также загружает MyPluginDLL. Я пытаюсь изменить метод в ThirdPartyDLL из MyPluginDLL, так что, когда MainProgram вызывает указанный метод, он вызовет измененный метод. Я хочу иметь возможность сделать это БЕЗ сохранения новой сборки и перезапуска MainProgram с новой сборкой. По сути, я хочу сделать это либо при запуске, либо при запуске MainProgram.

+0

Держу пари, что вы ищете [Mono.Cecil] (http://www.mono-project.com/Cecil). [Учебники находятся здесь] (http://stackoverflow.com/questions/1513319/mono-cecil-documentation-and-tutorials) – Measuring

+0

@ Измеряя, я знаю, что знаю. Но куда я смотрю? Я знаю только о 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); 
    } 
} 

0 Добавить следующую DLL с именем TargetDLL.dll в этот же каталог. Содержит этот код:

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

Редактировать

Я думаю, ваша ошибка связана с версией Mono.Cecil. Я использую 9.5.0 от master branch on GitHub. Загрузите ZIP-файл и при необходимости создайте проект.

+0

Я пробовал это измерение, но получаю эту ошибку: http: // pastebin.com/xPXJgn6k – user3150838

+0

Также, пожалуйста, проверьте изменения, которые я сделал в исходном сообщении. Надеюсь, это поможет вам понять. – user3150838

+0

Также будет ли ваш метод работать, если класс и метод нестационарны? – user3150838

Смежные вопросы