从VTable调用struct中的非托管函数

时间:2012-09-14 17:00:34

标签: c# .net unmanaged vtable

是否可以将函数从C#调用到结构中的非托管函数(通过VTable)。

例如,我正在进程中挂钩一个应用程序,我正在为每个类(应用程序)重新创建结构。

public struct SomeStruct {
   [FieldOffset(0x00)]
   public IntPtr * VTable;

   [FieldOffset(0x10)]
   public uint SomeValue;
}

然后,我通常会这样做:

var * data = (SomeStruct*)(Address);

我希望通过以下任一方式从结构的VTable中调用函数

Invoke<delegate>(data->VTable[0x3C])(delegateArguments)

或者

var eax = Invoke<Func<uint,uint>(data->VTable[0x3C])(arg1,arg2)

此外,这可以有效地完成(因为这些vtable funcs可以多次调用)?

也许是通过反射发射?

据我所知,每次调用Invoke<>函数时,编组都必须创建委托函数。

2 个答案:

答案 0 :(得分:2)

假设虚方法表包含指向函数的指针,假设您知道了偏移量(您看起来是这样做的),您可以通过调用IntPtr来获取ReadIntPtr method中的指针值。 {3}},如下:

IntPtr ptr = Marshal.ReadIntPtr(data.VTable, 0x3C);

然后你可以调用Marshal class上的GetDelegateForFunctionPointer method来获得相应类型的代表,如下所示:

// Assuming a signature of f(int, int) returning int
Func<int, int, int> func = (Func<int, int, int>)
    Marshal.GetDelegateForFunctionPointer(ptr, typeof(Func<int, int, int>));

然后你可以根据需要调用代理。

答案 1 :(得分:1)

好吧,我找到了一个可能的解决方案:

我创建了一个通用的Invoke方法,用于创建和缓存所有委托以供将来使用 还

 public void Select(uint target)
        {
            fixed (void* pThis = &this)
            {
                Generic.Invoke<Action<uint, uint>>(this.VTable[0xC0], CallingConvention.ThisCall)
                    ((uint)pThis, target);
            }
        }

        [FieldOffset(0x00)]
        public uint* VTable;

缓存:

  public static T Invoke<T>(uint addr, CallingConvention conv) where T : class
        {
          var type = typeof(T);
            if (!cache.Contains(type))
                cache.Set<T>(type, NativeHelper.GetDelegateForFunctionPointer<T>(addr, conv));

            return cache.Get<T>(type);
        }

创建函数的函数(适用于通用Func / Action)

public static T GetDelegateForFunctionPointer<T>(uint ptr, CallingConvention conv)
        where T : class
        {

            var delegateType = typeof(T);
            var method = delegateType.GetMethod("Invoke");
            var returnType = method.ReturnType;
            var paramTypes =
                method
                .GetParameters()
                .Select((x) => x.ParameterType)
                .ToArray();
            var invoke = new DynamicMethod("Invoke", returnType, paramTypes, typeof(Delegate));
            var il = invoke.GetILGenerator();
            for (int i = 0; i < paramTypes.Length; i++)
                il.Emit(OpCodes.Ldarg, i);
                il.Emit(OpCodes.Ldc_I4, ptr);

            il.EmitCalli(OpCodes.Calli, conv, returnType, paramTypes);
            il.Emit(OpCodes.Ret);
            return invoke.CreateDelegate(delegateType) as T;
        }