2012-09-14 52 views
4

是否可以從C#調用函數到結構中的非託管函數(通過VTable)。從VTable的struct中調用非託管函數

例如,我在進程中掛鉤一個應用程序,並且我正在爲每個類(應用程序)重新創建結構。

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

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

然後,我通常會做:

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

我想調用從結構的虛函數表的功能在以下任一方式

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

或者

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

此外,可能會有效地完成(因爲這些vtable funcs可能被稱爲無數次)?

也許通過反射發射?

從我所知道的情況來看,編組必須在每次調用Invoke<>函數時創建委託函數。

+0

指向「VTable」字段的指針是否正確?這是一個指向指針的指針,在這種情況下,它似乎是多餘的。 – casperOne

+0

@casperOne我認爲它是有意義的,如果你想把它作爲一個指針,所以你可以使用'data.VTable [0x3C]'而不是'ReadIntPtr()',正如你所建議的。 – svick

+0

@svick只是想確保它正確地被帶過來。 – casperOne

回答

2

鑑於虛擬方法表包含函數指針,假設你知道的偏移量(這似乎你這樣做),你可以通過調用Marshal classReadIntPtr method得到一個IntPtr指針值,就像這樣:

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

然後你就可以調用GetDelegateForFunctionPointer methodMarshal class才能獲得相應類型的委託,像這樣:

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

然後你就可以調用delegat根據需要。

+0

是的,我似乎得出了相同的結論(但我緩存的功能,我用通用GetDelegateForFunctionPointer)。這樣,調用func將不會有那麼多的性能損失 – Dan

+0

@Dan沒有理由不緩存它,該地址在它所加載的進程的生命週期內根本不會移位。 – casperOne

+0

是的,但casperOne,因爲我實際上並沒有存儲它自己的函數的引用,所以我需要一種緩存方式,所以我不會一直調用GetDelegateForFunctionPointer。看看我的答案在我作爲虛擬選擇函數的包裝器「選擇」功能 – Dan

1

好吧,我發現了一個可能的解決方案:

我已經創建,創建並緩存所有與會代表以備將來使用 此外

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; 

緩存通用的Invoke方法:

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