簡體   English   中英

C#攔截/更改/重定向方法

[英]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的版本有關。 在GitHubmaster分支上使用9.5.0 下載ZIP文件並根據需要構建項目。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM