1

I'm hooking a function in C# and I need to call it by it's original pointer afterwards (I'm restoring the original bytes before calling it)

I know that in C the following would work:

typedef void(__fastcall *tExecuteFunction)(int a1, __int64 a2);
tExecuteFunction oExecuteFunction = (tExecuteFunction)(0xABCDEF);
oExecuteFunction(0, 0);

However, I can't seem to find a proper way to do this in C#. I've tried the following:

void HookedFunction(int a1, IntPtr a2){
    //Do stuff
    hookedFunction.Unhook();
    //MethodInfo of the hooked function
    hookedFunction.OriginalMethod.Invoke(this, new object[] {a1, a2});
    hookedFunction.Hook();
}

I also tried to play around with the following:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void tExecuteFunction(int a1, __int64 a2);

but I can't seem to figure out how to give it a pointer like we can do in C. The original function pointer is stored in: hookedFunction.OriginalMethod.MethodHandle.GetFunctionPointer()

1
  • 1
    if you are trying to dynamically assign a function to a variable to pass it and invoke it in other functions, consider the C# Func, Action and Delegates. They serve that purpose. Commented Aug 19, 2018 at 2:12

2 Answers 2

3

I have to mention it first that CallingConvention.FastCall is not supported, please take a look here.

Here's the hook class:

// Author: Moien007
public unsafe class Hook
{
    const string KERNEL32 = "kernel32.dll";

    [DllImport(KERNEL32)]
    static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, VirtualProtectionType flNewProtect, out VirtualProtectionType lpflOldProtect);

    private enum VirtualProtectionType : uint
    {
        Execute = 0x10,
        ExecuteRead = 0x20,
        ExecuteReadWrite = 0x40,
        ExecuteWriteCopy = 0x80,
        NoAccess = 0x01,
        Readonly = 0x02,
        ReadWrite = 0x04,
        WriteCopy = 0x08,
        GuardModifierflag = 0x100,
        NoCacheModifierflag = 0x200,
        WriteCombineModifierflag = 0x400
    }

    private byte[] m_OriginalBytes;

    public IntPtr TargetAddress { get; }
    public IntPtr HookAddress { get; }

    public Hook(IntPtr target, IntPtr hook)
    {            
        if (Environment.Is64BitProcess)
            throw new NotSupportedException("X64 not supported, TODO");

        TargetAddress = target;
        HookAddress = hook;

        m_OriginalBytes = new byte[5];
        fixed (byte* p = m_OriginalBytes)
        {
            ProtectionSafeMemoryCopy(new IntPtr(p), target, m_OriginalBytes.Length);
        }
    }

    public void Install()
    {
        var jmp = CreateJMP(TargetAddress, HookAddress);
        fixed (byte* p = jmp)
        {
            ProtectionSafeMemoryCopy(TargetAddress, new IntPtr(p), jmp.Length);
        }
    }

    public void Unistall()
    {
        fixed (byte* p = m_OriginalBytes)
        {
            ProtectionSafeMemoryCopy(TargetAddress, new IntPtr(p), m_OriginalBytes.Length);
        }
    }

    static void ProtectionSafeMemoryCopy(IntPtr dest, IntPtr source, int count)
    {
        // UIntPtr = size_t
        var bufferSize = new UIntPtr((uint)count);
        VirtualProtectionType oldProtection, temp;

        // unprotect memory to copy buffer
        if (!VirtualProtect(dest, bufferSize, VirtualProtectionType.ExecuteReadWrite, out oldProtection))
            throw new Exception("Failed to unprotect memory.");

        byte* pDest = (byte*)dest;
        byte* pSrc = (byte*)source;

        // copy buffer to address
        for (int i = 0; i < count; i++)
        {
            *(pDest + i) = *(pSrc + i);
        }

        // protect back
        if (!VirtualProtect(dest, bufferSize, oldProtection, out temp))
            throw new Exception("Failed to protect memory.");
    }

    static byte[] CreateJMP(IntPtr from, IntPtr to)
    {
        return CreateJMP(new IntPtr(to.ToInt32() - from.ToInt32() - 5));
    }

    static byte[] CreateJMP(IntPtr relAddr)
    {
        var list = new List<byte>();
        // get bytes of function address
        var funcAddr32 = BitConverter.GetBytes(relAddr.ToInt32());

        // jmp [relative addr] (http://ref.x86asm.net/coder32.html#xE9)
        list.Add(0xE9); // jmp
        list.AddRange(funcAddr32); // func addr

        return list.ToArray();
    }
}
  • Find target function address (for example using GetProcAddress)
  • Define a delegate for that function
  • Use Marshal.GetDelegateForFunctionPointer and get delegate for target function so you call it inside your hook function
  • Define your hook function (I mean the function that will called instead of target)
  • Use Marshal.GetFunctionPointerForDelegate and get function pointer for your hook function
    (Note: assign the delegate to a static field or use GCHandle.Alloc to prevent GC from collecting it which leads to crash)
  • Now use Hook class

This technique isn't thread safe (more info on it), I recommend you to use EasyHook.

Sign up to request clarification or add additional context in comments.

Comments

1

Delegate works as pointer to a function, so you can call many functions whose are pointed by the delegate:

A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++."

Microsoft Docs about delegate

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.