これは EasyHook に関する特定の機能ではなく、一般的なフックに関する機能です。この署名で関数をフックしたい:
public: int __thiscall Connection_t::Send(unsigned int,unsigned int,void const *)
これは明らかに管理されていないコードであり、EasyHook を使用して管理されている C# コードでフックしようとしています
。
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);
しかし、フックを挿入するとすぐに、フックされたプログラムがクラッシュし続けます-大きな驚きではありません。それは呼び出し規約の問題であり、フック関数がフックされたプログラムのスタックに何らかの形で干渉していると思います。
そこで、同じ関数をフックする別のプロジェクトを見てみましたが、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();
そして、呼び出された関数:
__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++ でコンパイルされています)。元の関数を呼び出す前に、いくつかのレジスタを保存してスタックを修復する必要があると思いますか? または、私がここで間違っていることは何か他の考えはありますか?