[英]C# Intercept/change/redirect a method
假設我在第三方dll中有一個私有的,“實例”,非靜態的bool方法。 所有這個方法都返回一個值。 沒有其他的。 我將如何攔截對此方法的調用,更改它的IL OpCodes /方法體,或將其重定向到額外的,重寫或派生的方法。
我不想反編譯第三方DLL,手動更改源,並重新編譯它。 我也不想將程序集保存到磁盤,因為這也涉及使用“重新編譯”的程序集而不是原始程序集。
我基本上希望能夠使用原始的dll - 沒有替換或文件更改。 我只是想做我上面提到的。
有什么辦法可以解決這個問題嗎? 如果是這樣,你可以詳細說明或發布參考/教程/等。
另外,我知道虛擬,覆蓋和新修飾符,但請記住我:沒有所說的第三方dll的源,無法訪問源,不想用dotPeek和重新編譯等東西反編譯。
謝謝!
編輯:我忘了提及基礎架構的其余部分:MainProgram加載ThirdPartyDLL。 MainProgram還加載MyPluginDLL。 我正在嘗試從MyPluginDLL更改ThirdPartyDLL中的方法,以便當MainProgram調用所述方法時,它將調用更改的方法。 我希望能夠在不保存新裝配並使用新裝配重新啟動MainProgram的情況下執行此操作。 基本上,我想在啟動時或MainProgram運行時執行此操作。
下面是使用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的版本有關。 我在GitHub的master分支上使用9.5.0 。 下載ZIP文件並根據需要構建項目。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.