5

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関数は何度も呼び出される可能性があるため)?

おそらくリフレクションエミット経由?

私の知る限り、マーシャリングでは、関数を呼び出すたびにデリゲート関数を作成する必要がありますInvoke<>

4

2 に答える 2

3

仮想メソッドテーブルに関数へのポインタが含まれているとすると、オフセットがわかっていると仮定すると、次のように、MarshalクラスのメソッドIntPtrを呼び出すことででポインタ値を取得できます。ReadIntPtr

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

次に、クラスのGetDelegateForFunctionPointerメソッドを呼び出して、次のように適切なタイプのデリゲートを取得できます。Marshal

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

次に、必要に応じてデリゲートを呼び出すことができます。

于 2012-09-14T18:13:39.510 に答える
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;
        }
于 2012-09-14T18:35:14.153 に答える