DetourFunction Fehler



  • Hallo,
    ich arbeite gerade an einem Hook einer Funktion mittel MS Detours 1.5.
    Ich will die Funktion mehrmals hooken und unhooken, wo der Sinn ist, ist erstmal egal.
    Ich Hooke die Funktion via DetourFunction((PBYTE)&func, (PBYTE)&detour).
    Wenn ich Sie jetzt unhooke und wieder hooke wird während der Laufzeit mehr Speicher reserviert. Wenn ich mittels typecasts den Speicher freigebe und dann wieder hooke, gibt der Hook immer die gleiche Adresse zurück.
    Nun kommt es nach einigen Hooks jedoch zum Absturz, ich weiß nur leider nicht warum. Vielleicht weiß einer von euch warum das Programm dann einfach Abstürzt?
    Danke,
    Cloud



  • Hast du mal geschaut ob der Heap zerstört wird? Ist die Signatur deines Hooks exakt die Selbe, wie die der originalen API-Funktion?

    Was meinst du genau mit mehrmals hooken? Willst du an die selbe Funktion mehrere hooks anhängen, oder willst du die Funktion, die als hook ausgeführt werden soll, nur ändern?
    Bei letzterem könntest du ne Implementierung von mir ausprobieren, da ich auch schonmal detours benutzen wollte, aber auch probleme damit hatte.

    Hier die Klasse:

    apihook.h

    class API_Hook
    {
    private:
    	static const int SIZE = 6;
    	BYTE JMP[SIZE];
    	FARPROC pOrigDPMAddress;
    	DWORD oldProtect;
    	DWORD myProtect;
    	BYTE oldBytes[SIZE];
    
    	char module_name[512];
    	char api_name[512];
    	LPVOID hook_proc;
    
    public:
    	void hook_function();
    	void unhook_function();
    
    	void start_hook(); // this has to be called as first line of the hooked function
    	void end_hook(); // this has to be called as last line of the hooked function
    
    	API_Hook(LPCTSTR module_name, LPCSTR api_name, LPVOID hook_proc);
    };
    

    apihook.cpp

    void API_Hook::hook_function()
    {
    	JMP[0] = 0xE9;
    	JMP[1] = 0x90;
    	JMP[2] = 0x90;
    	JMP[3] = 0x90;
    	JMP[4] = 0x90;
    	JMP[5] = 0xC3;
    
    	DWORD JMPSize = ((DWORD)hook_proc - (DWORD)pOrigDPMAddress - 5);
    
    	VirtualProtect((LPVOID)pOrigDPMAddress, SIZE, PAGE_EXECUTE_READWRITE, &this->oldProtect);
    	memcpy(oldBytes, pOrigDPMAddress, SIZE);
    	memcpy(&JMP[1], &JMPSize, 4);
    	memcpy(pOrigDPMAddress, JMP, SIZE);
    	VirtualProtect((LPVOID)pOrigDPMAddress, SIZE, oldProtect, NULL);
    }
    
    void API_Hook::unhook_function()
    {
    	VirtualProtect((LPVOID)pOrigDPMAddress, SIZE, PAGE_EXECUTE_READWRITE, &oldProtect);
    	memcpy(pOrigDPMAddress, oldBytes, SIZE);
    	VirtualProtect((LPVOID)pOrigDPMAddress, SIZE, oldProtect, NULL);
    }
    
    API_Hook::API_Hook(LPCTSTR module_name, LPCSTR api_name, LPVOID hook_proc)
    {
    	this->pOrigDPMAddress = GetProcAddress(GetModuleHandle(module_name), api_name);
    	this->oldProtect = 0;
    	this->myProtect = PAGE_EXECUTE_READWRITE;
    
    	strcpy(this->module_name, module_name);
    	strcpy(this->api_name, api_name);
    	this->hook_proc = hook_proc;
    }
    
    void API_Hook::start_hook()
    {
    	VirtualProtect((LPVOID)pOrigDPMAddress, SIZE, myProtect, NULL);
    	memcpy(pOrigDPMAddress, oldBytes, SIZE);
    }
    
    void API_Hook::end_hook()
    {
    	memcpy(pOrigDPMAddress, JMP, SIZE);
    	VirtualProtect((LPVOID)pOrigDPMAddress, SIZE, oldProtect, NULL);
    }
    

    Und hier ein Beispiel, wie man es benutzt anhand der DispatchMessage API Funktion:

    // Dein Hook. Die Signatur muss genau der Signatur der originalen API-Funktion entsprechen. 
    LRESULT __stdcall hkDispatchMessage(CONST LPMSG lpMsg)
    {
       dispatch.start_hook(); // muss unbedingt an erster stelle des hooks stehen
    
       ... // hier machste halt was tolles
    
       dispatch.end_hook(); // muss unbedingt an letzter stelle des hooks stehen
    }
    
    int main()
    {
        API_Hook dispatch("user32.dll", "DispatchMessageA", hkDispatchMessage); // hook definieren
    
        dispatch.hook_function(); // aktiviert den hook
    
       ...
    }
    

    Wichtig ist, dass die Funktion erst nach dem Aufruf von end_hook returnen darf, da sonst die originale API Funktion nicht aufgerufen wird. Mit dispatch.unhook_function(); kannst du den hook wieder entfernen.



  • Stephan++ schrieb:

    Hast du mal geschaut ob der Heap zerstört wird? Ist die Signatur deines Hooks exakt die Selbe, wie die der originalen API-Funktion?

    Meinst du mit Signatur die Adresse? Also die Adresse des Hooks bleibt genau die gleiche. Ich gebe den Speicher frei und hooke dann wieder, dadurch bleibt die Adresse gleich.
    Wie meinst du Heap zerstören? Im Heap gebe ich alles unnötige wieder frei, daher kann ich nicht irgendwie zu viel Speicher reservieren. Merkwürdig vorallem, dass die Intervalle unterschiedlich sind. Manchmal bricht das Programm nach 2h ab, manchmal nach 30 Minuten.

    Stephan++ schrieb:

    Was meinst du genau mit mehrmals hooken? Willst du an die selbe Funktion mehrere hooks anhängen, oder willst du die Funktion, die als hook ausgeführt werden soll, nur ändern?

    Ich Hooke die Funktion, unhooke sie und hooke sie dann wieder, also nur ein Hook an die selbe Funktion, nur eben mit unhook dazwischen. Also könnte deins hinkommen. Werde ich mir gleich mal angucken.

    Stephan++ schrieb:

    Bei letzterem könntest du ne Implementierung von mir ausprobieren, da ich auch schonmal detours benutzen wollte, aber auch probleme damit hatte.

    //code gekürzt
    

    Wichtig ist, dass die Funktion erst nach dem Aufruf von end_hook returnen darf, da sonst die originale API Funktion nicht aufgerufen wird. Mit dispatch.unhook_function(); kannst du den hook wieder entfernen.

    Bin noch ein wenig "neu" in c++, daher muss ich die gleich erstmal verstehen 😃
    Danke für die Antwort 🙂



  • So... habe mich jetzt mal registriert. Sorry für den Doppelpost, aber geht leider nicht anders.
    Also dein Hook ist ja quasi der Detourfunction sehr ähnlich.
    Könnte ich damit so oft ich wollte
    dispatch.hook_function();
    und
    dispatch.unhook_function();
    aufrufen?
    Denn genau daran scheitert es bei mir.
    Wenn ich hooke, bisschen warte, unhooke und wieder hooke, dann kommt ab und zu ein Fehler, und wie gesagt in unbekannten Intervallen. Manchmal ziemlich schnell, manchmal langsam.
    Das Programm läuft ungefähr noch 2-3 Sekunden nach dem letzten Hook, dann bricht es zusammen... Also muss da irgendetwas schiefgehen.
    Hook sagt aber dass es wieder gehookt wurde (E9), aber keine Ahnung woher der fehler leider kommt.
    Danke für die Hilfe!
    //edit: jetzt zum beispiel läuft es schon wieder >4600sekunden ohne probleme
    //edit2: >5440 sekunden... werde aber jetzt mal schlafen gehen 😕
    //edit3: und wie würdest du einen nebenbeilaufenden thread öffnen? mit _beginthread? (also der soll den normalen thread nicht pausieren... :s



  • Hookst/Unhookst du eigentlich während das Programm die Funktionen aufruft? Erstmal würde ich nämlich pauschal davon ausgehen, dass das nicht threadsafe ist.



  • Morle schrieb:

    Hookst/Unhookst du eigentlich während das Programm die Funktionen aufruft? Erstmal würde ich nämlich pauschal davon ausgehen, dass das nicht threadsafe ist.

    Daran dachte ich auch schon... Ich habe mal an den Anfang der Funktion einen globalen Int wert auf 1 ändern lassen, welcher direkt vor dem Return auf 0 gesetzt wird.
    Wenn ich beim Hooken/Unhooken diesen Wert ausgeben lasse, hat er immer den Wert 0, daher hab ich das dann ausgeschlossen 😕 ich werde dem aber nochmal auf die Spur gehen. Kann es vielleicht an _beginthread liegen? ich hab darin ne while(1), vielleicht bringt dieser Loop die Funktion zum abstürzen? Danke 🙂



  • CloudFS schrieb:

    Meinst du mit Signatur die Adresse?

    Nein. Eine Signatur einer Funktion besteht aus dem Namen der Funktion und aus den typen und der Reihenfolger der Parameter die sie hat. Der rückgabewert gehört nicht dazu. (Bei anderen Programmiersprachen teilweise schon)

    Beispiel:
    void foo(int apfel, int birne);
    int foo2(int kirsche, int bananne);
    float foo3(char* kiwi, int mandarine);

    Die Funktionen foo und foo2 haben die gleiche Signatur, foo3 hingegen eine andere. (http://de.wikipedia.org/wiki/Signatur_%28Programmierung%29)

    Wie meinst du Heap zerstören?

    Den Heap zerstörst du, wenn du z.B. über Arraygrenzen hinwegschreibst oder delete auf speicher ausführst, auf den bereits delete ausgeführt wurde bzw. kein Speicher mit new allokiert wurde. Du kannst das mit folgender Funktion prüfen, die ich mir mal gebastelt habe (Achtung, funktioniert nur wenn du als Debug kompilierst!):

    char* checkForHeapError()
    {
    	int heap_error = _heapchk();
    
    	switch(heap_error)
    	{
    	case _HEAPEMPTY:
    		return "HEAP EMPTY";
    
    	case _HEAPOK:
    		return "HEAP OK";
    
    	case _HEAPBADBEGIN:
    		return "HEAP BAD BEGIN";
    
    	case _HEAPBADNODE:
    		return "HEAP BAD NODE";
    
    	case _HEAPEND:
    		return "HEAP END";
    
    	case _HEAPBADPTR:
    		return "HEAP BAD PTR";
    
    	case _FREEENTRY:
    		return "FREE ENTRY";
    
    	case _USEDENTRY:
    		return "USED ENTRY";
    	}
    
    	return "INVALID RETURN VALUE"; // this line should never be executed
    }
    

    Wenn du als Rückgabewert etwas anderes als "HEAP OK" bekommst, ist dein heap kaputt. Das ist schlecht, da im Heap u.a. die Speicherverwaltung Stattfindet.

    Merkwürdig vorallem, dass die Intervalle unterschiedlich sind. Manchmal bricht das Programm nach 2h ab, manchmal nach 30 Minuten.

    Genau das ist ein Indiz dass du den Heap zerstört haben könntest, da dein Programm nicht unbedingt sofort abstürzen muss, sondern erst dann, wenn die zerstörten Informationen benötigt werden.

    Bin noch ein wenig "neu" in c++, daher muss ich die gleich erstmal verstehen 😃

    Du bist neu in C++ und legst gleich mit Hooks los? mutig mutig!



  • Stephan++ schrieb:

    CloudFS schrieb:

    Meinst du mit Signatur die Adresse?

    Nein. Eine Signatur einer Funktion besteht aus dem Namen der Funktion und aus den typen und der Reihenfolger der Parameter die sie hat. Der rückgabewert gehört nicht dazu. (Bei anderen Programmiersprachen teilweise schon)

    Beispiel:
    void foo(int apfel, int birne);
    int foo2(int kirsche, int bananne);
    float foo3(char* kiwi, int mandarine);

    Die Funktionen foo und foo2 haben die gleiche Signatur, foo3 hingegen eine andere. (http://de.wikipedia.org/wiki/Signatur_%28Programmierung%29)

    Okay, ja dann ist die Signatur richtig bzw. komplett gleich.

    Stephan++ schrieb:

    Wie meinst du Heap zerstören?

    Den Heap zerstörst du, wenn du z.B. über Arraygrenzen hinwegschreibst oder delete auf speicher ausführst, auf den bereits delete ausgeführt wurde bzw. kein Speicher mit new allokiert wurde. Du kannst das mit folgender Funktion prüfen, die ich mir mal gebastelt habe (Achtung, funktioniert nur wenn du als Debug kompilierst!):

    char* checkForHeapError()
    {
    	int heap_error = _heapchk();
    
    	switch(heap_error)
    	{
    	case _HEAPEMPTY:
    		return "HEAP EMPTY";
    
    	case _HEAPOK:
    		return "HEAP OK";
    
    	case _HEAPBADBEGIN:
    		return "HEAP BAD BEGIN";
    
    	case _HEAPBADNODE:
    		return "HEAP BAD NODE";
    
    	case _HEAPEND:
    		return "HEAP END";
    
    	case _HEAPBADPTR:
    		return "HEAP BAD PTR";
    
    	case _FREEENTRY:
    		return "FREE ENTRY";
    
    	case _USEDENTRY:
    		return "USED ENTRY";
    	}
    
    	return "INVALID RETURN VALUE"; // this line should never be executed
    }
    

    Wenn du als Rückgabewert etwas anderes als "HEAP OK" bekommst, ist dein heap kaputt. Das ist schlecht, da im Heap u.a. die Speicherverwaltung Stattfindet.

    Merkwürdig vorallem, dass die Intervalle unterschiedlich sind. Manchmal bricht das Programm nach 2h ab, manchmal nach 30 Minuten.

    Genau das ist ein Indiz dass du den Heap zerstört haben könntest, da dein Programm nicht unbedingt sofort abstürzen muss, sondern erst dann, wenn die zerstörten Informationen benötigt werden.

    Probiere ich gerade aus. Habe die malloc.h inkludiert und gucke mal was so passiert. Jedoch muss ich sagen, dass der Hook im Debugmode nicht funktioniert, habe es jetzt einmal als Release laufe und einmal als Debug, wobei nur bei dem Release der Hook auch wirklich das tut, was er soll.

    Stephan++ schrieb:

    Bin noch ein wenig "neu" in c++, daher muss ich die gleich erstmal verstehen 😃

    Du bist neu in C++ und legst gleich mit Hooks los? mutig mutig!

    [/quote]
    Ja, hatte ein wenig C vor kurzem in der Uni, habe aber so ein großes Interesse an C++ etc, dass ich mich sehr gerne damit beschäftige.
    Also was ich jetzt so herausgefunden habe:
    Es liegt ganz sicher an Detourfunction.
    Wenn ich den Pointer zuweise, der den Rücksprung des Hooks kennzeichne und dann neu hooken will, muss ich diesen zuerst wieder freigeben?
    Also es gibt folgende Varianten:
    *oHook=Detourfunction(x,y);
    Dann zum neu Hooken lediglich: Detourfunction(x,y); //dadurch wird nur der Hook neu gelegt, oHook aber nicht neu belegt (funktioniert, stürzt aber irgendwann ab)
    Oder: free(oHook); *oHook=Detourfunction(x,y); //dadurch behält oHook genau die gleiche Adresse, Hook funktioniert, stürzt aber irgendwann ab
    oder: *oHook=Detourfunction(x,y); //bei jedem aufruf erhält oHook eine neue Adresse, aber es funktioniert, stürzt aber auch irgendwann ab.
    Etwas anderes was ich vielleicht mal hinzufügen sollte, ich unhooke nicht selber, sondern dass Programm, welches meine dll startet.
    Ich checke also wann es geunhookt wurde, und will einen neuen Hook drüber legen.
    Gibt es sonst vielleicht eine Methode einen unhook der Methode zu verhindern? Das wäre glaube ich auch noch eine sehr gute Lösung.
    Ich danke dir 🙂

    p.s. Ich habe kein malloc() Befehl benutzt um oHook irgendwie Speicher zu geben, vielleicht liegt es daran? Wieviel Bytes braucht der Hook? 5?

    //1:im release build zeigt er vor und nach dem letzten hook "HEAP OK" an... im debug noch nichts passiert
    //2:debug immer noch nichts, da wurde aber auch nicht geunhookt...
    und der eine läuft jetzt schon die ganze zeit, wird aber noch abschmieren, ganz sicher. mittlerweile teste ich die methode ohne free und ohne neu beschreibung der variable oHook, sondern einfach nur noch die Detour, und das alle 20ms einmal um zu gucken, ob er abschmiert...
    //3:alles kackt ab. alles 😡 😞
    was jetzt am sinnvollsten wäre ist das unhooken zu umgehen...

    //4:okay, jetzt ist mir was neues aufgefallen. ich öffne einen neuen thread mit einer while darin, der einfach checkt und gegebenfalls hookt. wenn ich 50mal woanders hooke ist es kein problem, es bricht immer in diesem thread ab. der thread war vorher mit _beginthread geöffnet worden, jetzt mit Createthread, hilft beides aber nicht. d.h. der Fehler muss ja da irgendwo drin sein (?)
    //ok eben fand der fehler irgendwo anders statt... teste gerade nochmal wo es jetzt sein wird..



  • Neuer Beitrag nur zum pushen, damit moderatoren das hier sehen 🙂
    Habe das Problem gefunden. Es liegt tatsächlich an der Detour. Während der Hook noch läuft und sich die Adresse ändert durch einen neuen Hook kackt es ab. Danke an alle die versucht haben zu helfen! 🙂
    Lg, Cloud
    p.s. kann damit geclosed werden 😉



  • Bei der Api Hook Klasse sollte man noch FlushInstructionCache aufrufen.


Anmelden zum Antworten