【问题标题】:c# changing method's pointers .NET 3.5c#更改方法的指针.NET 3.5
【发布时间】:2016-08-29 19:23:54
【问题描述】:

我试图在运行时替换插件加载器中的方法(如Bukkit for Minecraft)。在这种情况下,我无法直接修改程序集文件。整个目的是能够判断方法何时被调用。并在必要时取消它们。加载插件后,我运行以下代码:

public static void PluginLoaded()
{
    replace();
}       

public static void replace()
{
    MethodInfo oldMethod, newMethod;
    oldMethod = typeof(<other assembly>).GetMethod("<method name>", BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic,null,new Type[]{typeof(ushort)},null);
    newMethod = typeof(NewEvents).GetMethod("<method name>", BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(ushort) }, null);
    RuntimeHelpers.PrepareMethod(oldMethod.MethodHandle);
    RuntimeHelpers.PrepareMethod(newMethod.MethodHandle);

    ReplaceInner(oldMethod, newMethod);
}

static void ReplaceInner(MethodInfo methodToReplace, MethodInfo methodToInject)
{
    unsafe
    {
        if (IntPtr.Size == 4)
        {
            int* inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + 2;
            int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2;
            *tar = *inj;
        }
        else
        {
            ulong* inj = (ulong*)methodToInject.MethodHandle.Value.ToPointer() + 1;
            ulong* tar = (ulong*)methodToReplace.MethodHandle.Value.ToPointer() + 1;
            *tar = *inj;
        }
    }
}

在原始程序尝试调用更改的方法之前,它工作正常。当它这样做时,整个程序停止,我得到一个access volation。我该如何解决这个问题?

【问题讨论】:

  • 我认为您的应用程序中有一个插件架构,并且正在尝试使用包装器逻辑来跟踪插件中的方法调用?您是否尝试过依赖注入框架,例如托管可扩展性框架或 Microsoft Unity?这些提供了在动态加载的程序集周围实现包装器以执行此类操作的方法。
  • 哪个版本的框架?
  • 试试吧,不要打电话给RuntimeHelpers.PrepareMethod()
  • @Mr Anderson 哦,对不起,它的 .NET 3.5。
  • 这个功能直到4.0才起作用。查看这个站点,特别是 cmets 线程,他们在其中讨论类型的内存映射在 3.5 和 4.0 之间是如何变化的。如果你更新你的框架,不管有没有RuntimeHelpers.PrepareMethod(),它都可以工作。如果无法升级框架,请参考原始示例。 codeproject.com/Articles/37549/…

标签: c# pointers code-injection access-violation jit


【解决方案1】:

您提供的功能特定于从 .Net 版本 4.0 开始的 CLR 的内存映射。以下是您的选择:

选项 1. 在您的计算机上升级 .NET Framework。这应该可以解决您的问题,而无需升级 Visual Studio。 https://www.microsoft.com/en-us/download/details.aspx?id=42643

选项 2. 更新您的 ReplaceInner() 方法以反映 .NET 框架 4.0 之前的类型和方法的内存映射:

static void ReplaceInner(MethodInfo methodToReplace, MethodInfo methodToInject)
{
    unsafe
    {
        if (IntPtr.Size == 4)
        {
            uint* tarPtr = (uint*)methodToReplace.MethodHandle.Value.ToPointer();
            uint* injPtr = (uint*)methodToInject.MethodHandle.Value.ToPointer();

            uint* tar = (uint*)*(tarPtr + 5) + 12;
            uint* inj = (uint*)*(injPtr + 5) + 12;
            *tar = *inj;
        }
        else
        {
            ulong* tarPtr = (ulong*)methodToReplace.MethodHandle.Value.ToPointer();
            ulong* injPtr = (ulong*)methodToInject.MethodHandle.Value.ToPointer();

            ulong* tar = (ulong*)*(tarPtr + 5) + 12;
            ulong* inj = (ulong*)*(injPtr + 5) + 12;
            *tar = *inj;
        }
    }
}

【讨论】:

  • @michaelbecker 我稍微更改了代码。试试这个。
  • @michaelbecker 这个异常是什么时候发生的?在运行ReplaceInner() 或调用新注入的方法时?
  • 调用 ReplaceInner() 时。使用 Try{}Catch{} 我发现它的代码就是这样做“*tar = *inj;”。(对于 x64 上的第二个作为 im)
  • @michaelbecker 我目前无法访问 64 位环境来调试此问题 - 我会尽可能提供帮助。
  • 在 x64 中为 *tar = *inj 引发 NullReferenceException。有谁知道如何让它在 x64 模式下工作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-05
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 2010-09-08
相关资源
最近更新 更多