Fge*_*Fge 1 c# assembly hook detours calling-convention
这不是关于EasyHook的特定功能,而是关于一般的挂钩.我想用这个签名挂钩一个函数:
public: int __thiscall Connection_t::Send(unsigned int,unsigned int,void const *)
Run Code Online (Sandbox Code Playgroud)
这显然是非托管代码,我正在尝试使用EasyHook将其与我的托管c#代码挂钩.但我认为这不是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);
Run Code Online (Sandbox Code Playgroud)
但是一旦我注入钩子,钩住的程序就会继续崩溃 - 没什么大惊喜.我认为它是调用约定的问题,并且我的钩子函数以某种方式干扰了钩子程序的堆栈.
所以我看看另一个项目谁挂钩相同的功能,但在c ++中弯路(挂钩部分):
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();
Run Code Online (Sandbox Code Playgroud)
和被调用的函数:
__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];
}
}
Run Code Online (Sandbox Code Playgroud)
(目标程序集和c ++示例都使用visual c ++编译).我想在调用原始函数之前我必须保存一些寄存器并修复堆栈吗?或者其他任何想法我在这里做错了什么?
您正在尝试挂钩C++类实例方法.它有一个隐藏的参数,这个.此参数通常通过带有__this调用约定的ECX寄存器传递.这就是Detours版本所做的.
实现这一点非常重要,必须尽早保留CPU寄存器值,特别是ECX.这需要一个使用机器代码的存根,当然在托管存根中没有机器代码.我怀疑EasyHook是否支持它,它肯定不会在功能列表中得到承诺.