Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call unmanaged function in struct from VTable

Is it possible to call functions from C#, to an unmanaged function in a struct (via VTable).

For example, I am in-process hooking an application, and I am re-creating the structs for each class (of the application).

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

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

Then, I usually do:

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

And I wish to call a function from the VTable of the structure in either of the following ways

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

Or

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

Furthermore, could this be done efficiently (as these vtable funcs could be called numerous times)?

Perhaps via Reflection Emit?

From what I know, marshalling has to create the delegate function every time I call the Invoke<> func.

like image 939
Dan Avatar asked Oct 06 '22 15:10

Dan


2 Answers

Given that a virtual method table contains pointers to functions, assuming you know the offset (which it appears you do) you can get the pointer value in an IntPtr by calling the ReadIntPtr method on the Marshal class, like so:

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

Then you can call the GetDelegateForFunctionPointer method on the Marshal class to get a delegate of the appropriate type, like so:

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

Then you can call the delegate as needed.

like image 116
casperOne Avatar answered Oct 13 '22 15:10

casperOne


Well, I have found a possible solution:

I have created a generic Invoke method that creates and caches all delegates for future use Also

 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;

Caches:

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

And the function that creates the function (and works for generic 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;
        }
like image 29
Dan Avatar answered Oct 13 '22 14:10

Dan