Sin gestionar la función de enganche, pila / registro de un problema en esta convención de llamada?

StackOverflow https://stackoverflow.com/questions/4340390

Pregunta

Esto no es una función particular sobre EasyHook sino de enganche en general. Quiero conectar una función con esta firma:

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

Este es claramente el código no administrado y estoy tratando de conectar con mi código C # administrado usando EasyHook.But Creo que no es EasyHook causando problemas aquí, pero mi Knowlegde de convenciones de llamada, etc ...
Esto es como defino DllImport y eliminar:

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

Pero el Programm enganchado sigue chocando tan pronto como me inyecto el gancho - no es gran sorpresa. Me supppose que es un problema de la convención de llamada y que mi función de enganche de alguna manera interfiere con la pila de la Programm enganchado.

Así que tuve un vistazo a otro proyecto que lo hacen enganchar la misma función pero con desvíos en C ++ (la parte de enganche):

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

Y la función llamada:

__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 montaje y c ejemplo ++ están ambos compilado con c visual ++). Creo que voy a tener que salvar algunos registros y reparar la pila antes de llamar a la función original? O cualquier otra idea de lo que estoy haciendo mal aquí?

¿Fue útil?

Solución

Está intentando conectar un método instancia de la clase C ++. Tiene un argumento escondido, este . Este argumento se pasa comúnmente a través del registro ECX con los __Este convención de llamada. Eso es lo que se ve que la versión desvíos hacer.

Obtener este derecho es bastante no trivial, los valores de los registros de la CPU deben ser preservadas temprano, ECX en particular. Para ello se requiere un código de máquina utiliza código auxiliar que, sin código de máquina en un trozo gestionado por supuesto. Dudo que EasyHook tiene ningún apoyo para ello, desde luego, no se promete en la lista de características.

Otros consejos

Parece que lo descubrió. @Hans Passant era correcto: Tengo que salvar el argumento this oculta. EasyHook tiene realmente cuidar para todo, pero esto (como limpiar el material .net). Como this es el primer argumento Simplemente hice añadirlo a mi función (connection es mi referencia 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);

No puedo explicar por qué esto funciona (también creo que comprendía la mayor parte de él :) Yo realmente debería volver atrás y aprender un poco más la teoría ensamblador / compilación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top