2010-12-02 5 views
1

Это не особая функция EasyHook, а о подключении в целом. Я хочу, чтобы подключить функцию с этой подписью:Неуправляемая функция hooking, проблема стека/регистрации с вызовом?

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

Это явно неуправляемый код, и я пытаюсь подключить его с управляемыми C# код, использующих EasyHook.But Я думаю, что это не 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); 

Но зацепило программа продолжает не врезаться, как только я впрыснуть крючок - не большой сюрприз. Я полагаю, что это проблема соглашения о вызовах и что моя функция привязки каким-то образом вмешивается в стек подключенной программы.

Так что я имел взгляд на другой проект, который действительно зацепить ту же функцию, но с обходами в 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]; 
    } 
} 

(Target сборка и пример C++ скомпилированы с визуальным 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