2010-12-02 4 views
1

これはEasyHookについての特定の機能ではなく、一般的なフックについての機能です。私はそれがEasyHookはここに問題を引き起こしていないと思う。これは明らかに、アンマネージコードであると私はEasyHook.Butを使用して、私のマネージC#のコードでそれをフックしようとしているアンマネージド関数のフック、呼び出し規約のスタック/レジスタの問題?

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

が、私のknowlegde:私はこのシグネチャを持つ関数をフックしたいです

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); 

しかし、フックプログラムの開発は、すぐに私はフックを注入としてクラッシュしないを続けている - は大きな驚きを:
...規則などを呼び出すにこれは私がDLLIMPORTを定義し、削除する方法です。私はそれが呼び出し規約の問題であり、フック関数が何らかの形でフックされたプログラムのスタックに干渉していると思います。

だから私は(フック部分)++と同じ機能をフックが、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

passant:ありがとう。最初の議論としてEXCを見ているのは解決策でした:) – Fge

0

私はそれを理解したように見えます。 @ハンス・パサントがそうだった:隠された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

解決策として彼の答えをマークするのはあなたのほうがいいでしょう。 –

関連する問題