C#拦截/修改/重定向方法 [英] C# Intercept/change/redirect a method

查看:1305
本文介绍了C#拦截/修改/重定向方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们说我有一个私人的,比如,在第三方DLL非静态,布尔方法。所有这些方法确实是返回一个值。没有其他的。我怎么会去拦截调用该方法,改变它的IL操作码/方法体,或将其重定向到一个额外的,重写或派生的方法。

Let's say I have a private, "instance," non-static, bool method in a third-party dll. All this method does is return a value. Nothing else. How would I go about intercepting calls to this method, changing it's IL OpCodes/method body, or redirecting it to an extra, overridden or derived method.

我不希望反编译的第三方DLL,手动更改信号源,并重新编译。
我也宁愿不向大会保存到磁盘,因为这也将使用重新编译集结号代替了原来的参与。

I do not want to decompile the third-party dll, manually change the source, and recompile it. I also would rather not to save the assembly to disk as this would also involve using a "recompiled" assembly instead of the original.

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

I basically want to be able to use the original dll - no replacements or file changes. I just want to do what I mentioned above.

有没有办法去了解呢?如果是这样,你能否详细说明或交引用/教程/等

Is there any way to go about this? If so, can you elaborate or post references/tutorials/etc.

另外,我知道虚拟的,覆盖的,和新的改性剂,但要记住我:没有的消息人士称第三方DLL,无法获得访问源,不想因为dotPeek一些诸如反编译和重新编译。

Also, I know of virtual, override, and new modifiers, but remember that I: do not have the source of said third-party dll, cannot get access to the source, do not want to decompile with something such as dotPeek and recompile.

谢谢!

编辑:
我忘了提及基础设施的其余部分:
MainProgram(主程序)负载ThirdPartyDLL。
MainProgram(主程序)还加载MyPluginDLL。
我试图从MyPluginDLL在ThirdPartyDLL改变方法,这样,当MainProgram(主程序)调用该方法,它将调用改变方法。我希望能够做到这一点,不保存新的组件并用新的装配重新启动MainProgram(主程序)。从本质上讲,我想无论是在启动时或当MainProgram(主程序)运行做到这一点。

I forgot to mention the rest of the infrastructure: MainProgram loads ThirdPartyDLL. MainProgram also loads MyPluginDLL. I'm trying to change a method in ThirdPartyDLL from MyPluginDLL so that when MainProgram calls said method, it will call the changed method. I want to be able to do this WITHOUT saving a new assembly and restarting the MainProgram with the new assembly. Essentially, I want to do this either at startup or when MainProgram is running.

推荐答案

下面是一个代码示例来更改集会在内存并执行它的方法,使用单声道塞西尔。注意,修改和保存装配是很慢的。这应该在你的应用程序的启动来完成。

Here is a code example to change an assembly in memory and execute methods on it, using Mono Cecil. Note that modifying and saving Assemblies is very slow. This should be done at startup of your application.

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);
    }
}



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

Add the following DLL with the name TargetDLL.dll in the same directory. Containing this code:

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

修改

我觉得你的错误与Mono.Cecil能做到的版本做。我使用的从GitHub上的主分支9.5.0 。下载ZIP文件并生成所需的项目。

I think your error has to do with the version of Mono.Cecil. I'm using 9.5.0 from the master branch on GitHub. Download the ZIP file and build the project as required.

这篇关于C#拦截/修改/重定向方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆