2010-12-02 21 views
1

Dies ist keine spezielle Funktion über EasyHook, sondern generell über das Anhaken. Ich möchte mit dieser Signatur eine Funktion Haken:Unmanaged Funktion Hooking, Stack/Register Problem mit Aufrufkonvention?

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

Dies ist eindeutig nicht verwalteten Code und ich versuche, es mit meinem verwalteten C# -Code Haken EasyHook.But mit Ich denke, es nicht ist EasyHook Probleme hier verursacht, aber meine WISSEN auf Konventionen etc Aufruf ...
Dies ist, wie ich DllImport definieren und löschen:

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

Aber das Haken Programm hält so schnell auf abstürzt, wie ich den Haken injizieren - keine große Überraschung. Ich vermute, dass es ein Problem der Aufrufkonvention ist und dass meine Hooking-Funktion irgendwie den Stack des hooked-Programms stört.

So hatte ich einen Blick auf ein anderes Projekt, die die gleiche Funktion Haken tun, sondern mit Umwegen in C++ (das Hakenteil):

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

Und die aufgerufene Funktion:

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

(Ziel Assembly und C++ - Beispiel werden beide mit visual C++ kompiliert. Ich denke, ich muss einige Register speichern und den Stapel reparieren, bevor ich die ursprüngliche Funktion anrufe. Oder irgendeine andere Idee, was ich hier falsch mache?

Antwort

7

Sie versuchen, eine C++ - Klasseninstanzmethode anzuhängen. Es hat ein verstecktes Argument, dieses. Dieses Argument wird üblicherweise über das ECX-Register mit der __dies Aufrufkonvention übergeben. Das sieht man in der Version von Detours.

Die richtige Einstellung ist ziemlich unwichtig, die CPU-Registerwerte müssen besonders bei ECX frühzeitig erhalten werden. Das erfordert einen Stub, der Maschinencode verwendet, natürlich keinen Maschinencode in einem verwalteten Stub. Ich bezweifle, dass EasyHook Unterstützung dafür hat, es ist sicherlich nicht in der Feature-Liste versprochen.

+0

passant: Danke. EXC als erstes Argument zu sehen war die Lösung :) – Fge

0

Sieht aus wie ich es herausgefunden habe. @ Hans Passant hatte Recht: Ich muss das versteckte this Argument speichern. EasyHook kümmert sich eigentlich um alles andere (wie das Aufräumen der .net-Sachen). Wie this das erste Argument ist einfach ich es zu meiner Funktion hinzugefügt haben (connection meine this Referenz):

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

kann nicht wirklich erklären, warum dies funktioniert (auch ich glaube, ich habe das meiste davon verstehen :) Ich sollte wirklich zurückgehen und etwas mehr Assembler-/Kompilierungstheorie lernen.

+0

Marking seine Antwort als die Lösung wäre nett von dir. –