Это не конкретная функция EasyHook, а функция перехвата в целом. Я хочу привязать функцию к этой сигнатуре:
public: int __thiscall Connection_t::Send(unsigned int,unsigned int,void const *)
Это явно неуправляемый код, и я пытаюсь зацепить его своим управляемым кодом на C # с помощью EasyHook, но я думаю, что здесь проблемы возникают не из-за EasyHook, а из-за моих познаний в соглашениях о вызовах и т. Д.
Вот как я определяю DllImport и удаляю:
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 ++). Я думаю, мне придется сохранить несколько регистров и восстановить стек, прежде чем я вызову исходную функцию? Или любая другая идея, что я здесь делаю не так?
2 ответа
Вы пытаетесь подключить метод экземпляра класса C ++. У него есть скрытый аргумент, this . Этот аргумент обычно передается через регистр ECX в соответствии с соглашением о вызовах __this. Это то, что вы видите в версии Detours.
Сделать это правильно довольно нетривиально, значения регистров ЦП должны быть сохранены заранее, в частности ECX. Для этого требуется заглушка, в которой используется машинный код, конечно, машинный код в управляемой заглушке отсутствует. Я сомневаюсь, что у EasyHook есть какая-либо поддержка для этого, это определенно не обещано в списке функций.
Похоже, я понял это. @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 = "?Send@Connection_t@@QAEHIIPBX@Z", 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);
Не могу объяснить, почему это работает (также я думаю, что понял большую часть этого :) Мне действительно нужно вернуться и изучить немного больше теории ассемблера / компиляции.
Похожие вопросы
Новые вопросы
c#
C# (произносится как «see Sharp») — это высокоуровневый мультипарадигменный язык программирования со статической типизацией, разработанный Microsoft. Код C# обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, которое включает в себя .NET, .NET Framework, .NET MAUI и Xamarin среди прочих. Используйте этот тег для ответов на вопросы о коде, написанном на C#, или о формальной спецификации C#.