如何在运行时将 IL 注入到方法中

发布于 2024-10-14 16:03:59 字数 1679 浏览 3 评论 0原文

标题或多或少说明了一切。基于这篇文章,我想出了这个:

public static unsafe void Replace(this MethodBase destination, MethodBase source)
{
    IntPtr srcHandle = source.MethodHandle.GetFunctionPointer();
    IntPtr dstHandle = destination.MethodHandle.GetFunctionPointer();

    int* dstPtr = (int*)dstHandle.ToPointer();
    *dstPtr = srcHandle.ToInt32();
}

这确实有效。 .. 偶尔 -.-

例如,这有效。

public static class Program
{
    public static void Main(string[] args)
    {
        MethodInfo methodA = typeof(Program).GetMethod("A", BindingFlags.Public | BindingFlags.Static);
        MethodInfo methodB = typeof(Program).GetMethod("B", BindingFlags.Public | BindingFlags.Static);

        methodA.Replace(methodB);

        A();
        B();
    }

    public static void A()
    {
        Console.WriteLine("Hai World");
    }

    public static void B()
    {
        Console.WriteLine("Bai World");
    }
}

然而,这不是(SEHException)。我所做的只是更改函数定义的顺序。

public static class Program
{
    public static void Main(string[] args)
    {
        MethodInfo methodA = typeof(Program).GetMethod("A", BindingFlags.Public | BindingFlags.Static);
        MethodInfo methodB = typeof(Program).GetMethod("B", BindingFlags.Public | BindingFlags.Static);

        methodA.Replace(methodB);

        A();
        B();
    }

    public static void B()
    {
        Console.WriteLine("Bai World");
    }

    public static void A()
    {
        Console.WriteLine("Hai World");
    }
}

至于文章中的代码...我根本无法让它工作。

有什么想法/替代方案吗?

Title more or less says it all. Based on this article, I've come up with this:

public static unsafe void Replace(this MethodBase destination, MethodBase source)
{
    IntPtr srcHandle = source.MethodHandle.GetFunctionPointer();
    IntPtr dstHandle = destination.MethodHandle.GetFunctionPointer();

    int* dstPtr = (int*)dstHandle.ToPointer();
    *dstPtr = srcHandle.ToInt32();
}

This actually works... occasionally -.-

For example, this works.

public static class Program
{
    public static void Main(string[] args)
    {
        MethodInfo methodA = typeof(Program).GetMethod("A", BindingFlags.Public | BindingFlags.Static);
        MethodInfo methodB = typeof(Program).GetMethod("B", BindingFlags.Public | BindingFlags.Static);

        methodA.Replace(methodB);

        A();
        B();
    }

    public static void A()
    {
        Console.WriteLine("Hai World");
    }

    public static void B()
    {
        Console.WriteLine("Bai World");
    }
}

However, this doesn't (SEHException). All I did was change the order in which the functions were defined.

public static class Program
{
    public static void Main(string[] args)
    {
        MethodInfo methodA = typeof(Program).GetMethod("A", BindingFlags.Public | BindingFlags.Static);
        MethodInfo methodB = typeof(Program).GetMethod("B", BindingFlags.Public | BindingFlags.Static);

        methodA.Replace(methodB);

        A();
        B();
    }

    public static void B()
    {
        Console.WriteLine("Bai World");
    }

    public static void A()
    {
        Console.WriteLine("Hai World");
    }
}

As for the code in the article... I couldn't get it to work at all.

Any ideas/alternatives?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空城缀染半城烟沙 2024-10-21 16:03:59

这会做出很多错误的假设,这些假设会咬你的屁股。

首先,无论如何,通过反射返回的结构都不能保证指向任何运行时结构。因此,尝试修改它包含或返回的指针是完全错误的。

其次,如果您希望执行诸如注入前/后方法调用不变量之类的操作(作为示例),那么您可能应该构造运行时代理对象并注入它们。或者通过 Emit 命名空间使用动态方法构造。尝试通过未记录/未知的行为(例如上面的代码)来操纵事物是行不通的。

您还需要意识到 JIT 决定它何时运行。有时它针对整个类运行,有时它只针对单个方法运行。您的代码不会尝试确定该方法是否已被 JITted,并且盲目地假设返回的函数指针可以修改。

This is making a lot of bad assumptions which will bite you in the ass.

First things first, the structure returned via reflection is not guaranteed, in any way, to point to any runtime structures at all. As such attempting to modify the pointers it contains or returns is just plain wrong.

Secondly, if you wish to do something like injecting pre/post method call invariants (as an example) then you should probably construct runtime proxy objects and inject those instead. Or use dynamic method construction through the Emit namespace. Attempting to manipulate things through undocumented/unknown behaviors (such as the above code) just wont work.

You also need to realize that the JIT decides when it will run. Sometimes it runs against an entire class, and sometimes it just runs against a single method. Your code makes no attempt at determining if the method has been JITted yet, and blindly assumes that the function pointer returned can be modified.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文