This is not a particular function about EasyHook but about hooking in general. I want to hook a function with this signature:
public: int __thiscall Connection_t::Send(unsigned int,unsigned int,void const *)
This is clearly unmanaged code and I'm trying to hook it with my managed c# code using EasyHook.But I think it's not EasyHook causing problems here but my knowlegde on calling conventions etc...
This is how I define DllImport and delete:
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);
But the hooked programm keeps on crashing as soon as I inject the hook - no big surprise. I supppose it's a problem of the calling convention and that my hooking-function somehow interferes with the stack of the hooked programm.
So I had a look at another project who do hook the same function but with detours in c++ (the hooking part):
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();
And the called function:
__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];
}
}
(Target assembly and c++ example are both compiled with visual c++). I guess I'll have to save some registers and repair the stack before I call the original function? Or any other idea what I'm doing wrong here?
You are trying to hook a C++ class instance method. It has a hidden argument, this. This argument is commonly passed through the ECX register with the __this calling convention. That's what you see that Detours version doing.
Getting this right is quite untrivial, the CPU register values must be preserved early, ECX in particular. That requires a stub that uses machine code, no machine code in a managed stub of course. I doubt that EasyHook has any support for it, it certainly isn't promised in the feature list.