2010-12-02 122 views
1

Ce n'est pas une fonction particulière de EasyHook mais de l'accrochage en général. Je veux accrocher une fonction avec cette signature:Accroissement de fonction non géré, problème de pile/enregistrement avec convention d'appel?

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

Ceci est clairement le code non managé et je suis en train de le brancher avec mon code managé C# en utilisant EasyHook.But Je pense que ça EasyHook ne pas causer de problèmes ici, mais mon knowlegde sur les conventions d'appel etc ...
Voilà comment je définis DllImport et supprimer:

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

Mais le programm accroché continue à s'écraser dès que j'Injecter le crochet - pas une grande surprise. Je suppose que c'est un problème de la convention d'appel et que ma fonction d'accrochage interfère d'une manière ou d'une autre avec la pile du programme accroché.

J'ai regardé un autre projet qui ne crochet la même fonction, mais avec des détours en C++ (la partie d'accrochage):

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

Et la fonction appelée:

__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]; 
    } 
} 

(cible assembly et l'exemple C++ sont tous deux compilés avec visual C++). Je suppose que je vais devoir enregistrer des registres et réparer la pile avant d'appeler la fonction d'origine? Ou toute autre idée de ce que je fais mal ici?

Répondre

7

Vous essayez de connecter une méthode d'instance de classe C++. Il a un argument caché, ce. Cet argument est généralement passé par le registre ECX avec la convention d'appel __this. C'est ce que vous voyez dans la version de Detours.

Si l'on ne remédie pas à ce problème, les valeurs du registre CPU doivent être conservées précocement, en particulier ECX. Cela nécessite un talon qui utilise le code machine, pas de code machine dans un bout managé bien sûr. Je doute que EasyHook ait un support pour cela, ce n'est certainement pas promis dans la liste des fonctionnalités.

+0

passant: Merci. Voyant EXC comme le premier argument était la solution :) – Fge

0

On dirait que je l'ai compris. @ Hans Passant avait raison: je dois enregistrer l'argument caché this. EasyHook prend vraiment soin de tout sauf de cela (comme nettoyer les choses .net). Comme this est le premier argument que je simplement ai ajouté à ma fonction (connection est ma référence 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); 

peut-il expliquer pas vraiment pourquoi cela fonctionne (aussi je pense que je ne comprenais plus de celui-ci :) Je devrais vraiment revenir en arrière et apprendre plus de théorie de l'assembleur/compilateur.

+0

Marquer sa réponse comme la solution serait gentil de votre part. –