【问题标题】:C# calling a function from it's memory addressC#从它的内存地址调用一个函数
【发布时间】:2018-08-19 02:04:09
【问题描述】:

我在 C# 中挂钩一个函数,之后我需要通过它的原始指针调用它(我在调用它之前恢复原始字节)

我知道在 C 中可以使用以下方法:

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

但是,我似乎无法在 C# 中找到合适的方法来执行此操作。 我尝试了以下方法:

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

我也尝试过以下方法:

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

但我似乎不知道如何像我们在 C 中那样给它一个指针。原始函数指针存储在: hookedFunction.OriginalMethod.MethodHandle.GetFunctionPointer()

【问题讨论】:

  • 如果您尝试将函数动态分配给变量以传递它并在其他函数中调用它,请考虑 C# Func、Action 和 Delegates。他们服务于这个目的。

标签: c# callback


【解决方案1】:

必须先提一下CallingConvention.FastCall不支持,请看here

这是钩子类:

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

此技术不是线程安全的 (more info on it),我建议您使用 EasyHook

【讨论】:

    【解决方案2】:

    Delegate 用作指向函数的指针,因此您可以调用委托所指向的许多函数:

    委托是一种安全封装方法的类型,类似于 C 和 C++ 中的函数指针。”

    Microsoft Docs about delegate

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-09
      • 1970-01-01
      • 2012-02-13
      • 2014-10-12
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多