c# - 非托管函数 Hook ,调用约定的堆栈/注册问题?

标签 c# assembly hook calling-convention detours

这不是关于 EasyHook 的特定功能,而是关于一般的 Hook 。我想用这个签名 Hook 一个函数:

public: int __thiscall Connection_t::Send(unsigned int,unsigned int,void const *)

这显然是非托管代码,我正在尝试使用 EasyHook 将它与我的托管 C# 代码 Hook 。但我认为这不是 EasyHook 导致这里出现问题的原因,而是我在调用约定等方面的知识......
这就是我定义 DllImport 和删除的方式:

    public static int Send_Hooked(uint connection, uint size, IntPtr pDataBlock)
    {
        return Send(connection, size, pDataBlock);
    }

    [DllImport("Connection.dll", EntryPoint = "?Send@Connection_t@@QAEHIIPBX@Z", CallingConvention = CallingConvention.ThisCall)]
    static extern int Send(uint connection, uint size, IntPtr pDataBlock);

    [UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Unicode, SetLastError = true)]
    delegate int DSend(uint connection, uint size, IntPtr pDataBlock);

但是一旦我注入(inject)钩子(Hook),被钩子(Hook)的程序就会继续崩溃——这并不奇怪。我认为这是调用约定的问题,我的 Hook 函数以某种方式干扰了 Hook 程序的堆栈。

所以我看了另一个项目,它确实 Hook 了相同的函数,但在 C++ 中绕了弯路( Hook 部分):

Func =  (int (__stdcall *)(unsigned int, unsigned short, void const ))::GetProcAddress(::GetModuleHandle("Connection.dll"), "?Send@Connection_t@@QAEHIIPBX@Z");
PVOID DetourPtr;
PVOID TargetPtr;
DetourTransactionBegin();
DetourAttachEx(&Func, SendConnectionHook, &Trampoline, &TargetPtr, &DetourPtr );
DetourTransactionCommit();

以及被调用的函数:

__declspec(naked) void SendConnectionHook (CPU_CONTEXT saved_regs, void * ret_addr, WORD arg1, DWORD arg2, DWORD arg3)
{
    DWORD edi_value;
    DWORD old_last_error;

    __asm
    {
        pushad;   /* first "argument", which is also used to store registers */
        push ecx; /* padding so that ebp+8 refers to the first "argument" */

        /* set up standard prologue */
        push ebp;
        mov ebp, esp;
        sub esp, __LOCAL_SIZE;
    }

    edi_value = saved_regs.edi;
    old_last_error = GetLastError();
    OnConnectionSend((void *) saved_regs.ecx, (unsigned char *) arg3, arg2);
    SetLastError(old_last_error);

    __asm
    {
        /* standard epilogue */
        mov esp, ebp;
        pop ebp;

        pop ecx; /* clear padding */
        popad; /* clear first "argument" */
        jmp [Trampoline];
    }
}

(目标程序集和 c++ 示例均使用 visual c++ 编译)。我想我必须在调用原始函数之前保存一些寄存器并修复堆栈?或者我在这里做错了什么?

最佳答案

您正在尝试 Hook C++ 类实例方法。它有一个隐藏的参数,this。此参数通常使用 __this 调用约定通过 ECX 寄存器传递。这就是您看到的 Detours 版本所做的。

要做到这一点非常重要,必须尽早保留 CPU 寄存器值,尤其是 ECX。这需要一个使用机器代码的 stub ,当然托管 stub 中没有机器代码。我怀疑 EasyHook 是否支持它,功能列表中肯定没有 promise 。

关于c# - 非托管函数 Hook ,调用约定的堆栈/注册问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4340390/

相关文章:

assembly - 变量应该在寄存器中存储多长时间?

dll - 为什么我们必须将全局钩子(Hook)过程放在单独的 DLL 中

c++ - 如何在不使用 CreateWindow(Ex) 的情况下创建窗口 (HWND)?

c# - 如何在C#中使用zKemKeeper连接考勤机?

c# - 无法将土耳其语字符从文本文件读取到字符串数组

assembly - 为什么 MIPS 指令 "add"有时会给我一个算术错误,但并非总是如此?

java - 将手势映射到按键命令

c# - 使用 ClosedXML 如何根据内容调整行高?

c# - 为什么 GDI+ 会截断缩放后的图像?

c - linux 汇编程序如何乘除 64 位数字?