2010-12-02 44 views
1

這不是關於EasyHook的特殊功能,而是關於通用鉤子的特殊功能。我要掛鉤函數與此簽名:非託管函數掛鉤,堆棧/註冊調用約定的問題?

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

這顯然是託管代碼,我想用我的EasyHook.But託管的C#代碼,把它掛,我認爲它不是EasyHook這裏造成的問題,但我knowlegde在調用約定等...
我這是怎麼定義的DllImport和刪除:

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

    [DllImport("Connection.dll", EntryPoint = "[email protected][email protected]@[email protected]", 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); 

但迷上PROGRAMM不斷,只要我注入鉤崩潰 - 沒有什麼大的驚喜。我認爲這是調用約定的問題,並且我的掛鉤函數以某種方式干擾了所掛鉤的程序堆棧。

所以我不得不來看看另一個項目誰做勾相同的功能,但在C彎路++(掛鉤部):

Func = (int (__stdcall *)(unsigned int, unsigned short, void const))::GetProcAddress(::GetModuleHandle("Connection.dll"), "[email protected][email protected]@[email protected]"); 
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++編譯的)。我想在調用原始函數之前,我必須保存一些寄存器並修復堆棧?或者其他任何想法我在這裏做錯了嗎?

回答

7

您試圖掛鉤一個C++類實例方法。它有一個隱藏的參數,這個。這個參數通常通過__這個調用約定通過ECX寄存器。這就是你看到Detours版本正在做的事情。

獲得這個權利是相當平淡的,CPU寄存器值必須提前保存,特別是ECX。這需要使用機器代碼的存根,當然,在託管存根中沒有機器代碼。我懷疑EasyHook是否有任何支持,它在功能列表中肯定沒有答應。

+0

傳承者:謝謝。看到EXC作爲第一個參數是解決方案:) – Fge 2010-12-04 23:15:17

0

看起來像我想出來的。 @Hans Passant是對的:我必須保存隱藏的this參數。 EasyHook確實照顧了一切,但是這(例如清理.net的東西)。由於this是第一個參數我根本沒把它添加到我的功能(connection是我this參考):

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

    [DllImport("Connection.dll", EntryPoint = "[email protected][email protected]@[email protected]", CallingConvention = CallingConvention.ThisCall)] 
    static extern int Send(IntPtr connection, uint unknown, uint size, IntPtr pDataBlock); 

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

真的不能解釋爲什麼這樣做的工作(我也覺得我沒明白大部分:)我真的應該回去學習更多的彙編/編譯理論。

+0

標記他的答案作爲解決方案將是很好的你。 – 2010-12-15 09:10:10