WinApi hooken?



  • ganz einfach:

    die ersten 5 byte der funktion wurde überschrieben und durch einen farcall
    ersetzt, also dem opcode für den sprung an deine eigene funktion.

    sämtliche funktionen der winapi nutzen die stdcall aufrufkonvention. diese
    funktionen beginnen aufgrund der konvention immer mit den selben 5 bytes.

    push ebp
    mov ebp, esp
    sub esp, xx

    (xx steht für die größe aller lokalen variablen)

    diese wurden überschrieben. um die funktion dennoch aufrufen zu können,
    muss man diese selber ausführen, z.b. mit inline-assembler

    __declspec(naked) DWORD callfunc(void * func) // verhindert dass der kompiler den funktionsprolog hinzufügt
    {
        char *addr = reinterpret_cast<char *>(func) + 5; // 5 bytes weiter
        __asm
        {
            mov ebx, addr // hier speichern wir die addresse
            push ebp
            mov ebp, esp
            sub esp, xx // !!
            jmp ebx
        }
    }
    

    hier haben wir allerdings ein problem, denn wir wissen nicht wieviele variablen
    die funktion auf den stack legt.

    wenn wir zuwenig nehmen überschreiben wir die rücksprungaddresse und den framepointer.
    wenn wir zuviel nehmen, kann es sein dass das selbe problem auftrifft,
    es kann aber auch sein, dass der wert von ebp genommen wird statt die selbe
    größe wieder auf den esp zu addieren. hier weiß ich nicht genau wie die
    winapi das macht, ich befürchte beide versionen gibt es.

    lässt sich bestimmt auch lösen, aber dazu müsste man die funktion
    disassemblieren und ....

    aber ich weiß nicht ob dir das viel bringt, da du die grundlagen verstanden
    haben musst. was dein letzer post nur bestätigt.

    guck dir mal die links an und versuch alles zu verstehen.

    edit:

    klempfner schrieb:

    es gibt jawoll viele möglichleiten api hooking zu betrieben stichwort IAT und viele andere

    es war nur ein beispiel. natürlich gibt es noch viele andere möglichkeiten 🙂



  • helferlein schrieb:

    sämtliche funktionen der winapi nutzen die stdcall aufrufkonvention. diese
    funktionen beginnen aufgrund der konvention immer mit den selben 5 bytes.

    push ebp
    mov ebp, esp
    sub esp, xx

    (xx steht für die größe aller lokalen variablen)

    Aber dann hät ich da mal ne Frage:

    Warum hat dann z.B. FindNextFileW diese ersten 12Bytes:

    6A 2C             PUSH 2C
    68 C8F0807C       PUSH kernel32.7C80F0C8
    E8 0035FFFF       CALL kernel32.7C8024D6
    

    Zumindestens laut Olly?

    Gruß Pingu



  • weil's nur'n stub is 💡



  • nehmen wir mal an es handelt sich um SetCurserPos

    #include <windows.h>
    #include <iostream>
    
    using namespace std;
    
    BOOL WINAPI __stdcall SetCursorPosA(int x, int y);
    DWORD DLLFunc;
    
    int main()
    {
    	Sleep(2000);
    	HINSTANCE hInst = LoadLibrary(TEXT("user32.dll"));
        DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos") + 5;  
    	bool somebool = SetCursorPosA(0, 0);
    
    	return 0;
    }
    
    BOOL WINAPI __stdcall SetCursorPosA(int x, int y)
    {
       __asm
       {
          mov  edi, edi
          push ebp
          mov  ebp, esp
          jmp [DLLFunc]
       }
    }
    

    Warum crashed das programm?



  • tester312 schrieb:

    BOOL WINAPI __stdcall SetCursorPosA(int x, int y)
    {
       __asm
       {
          mov  edi, edi
          push ebp
          mov  ebp, esp
          jmp [DLLFunc]
       }
    }
    

    Warum crashed das programm?

    Hi,
    ich würd behaupten das, dass Problem is das du bei jmp ein Offset angeben musst und nicht die Adresse die du z.B. von GetProcAddress() bekommts.
    Und das Offset wäre: Ziel-Absprung.
    Desweiteren wird doch ,wenn du das so machst, der Prolog deiner Funktion + der Prolog von SetCursorPos aufgerufen. Das sollte au nicht so gut sein.
    Schreib lieber statt:

    BOOL WINAPI __stdcall SetCursorPosA(int x, int y)
    

    was zumal sowieso komisch is da ja WINAPI nur ein #define für __stdcall ist,

    BOOL __declspec(naked) SetCursorPosA(int x, int y)
    

    Somit haste kein Prolog und es sollte funktionieren.

    Gruß Pingu



  • 'SetCursorPosA': 'naked' kann nur auf nicht-Memberfunktionsdefinitionen angewendet werden



  • #include <windows.h>
    #include <iostream>
    
    using namespace std;
    
    DWORD DLLFunc;
    BOOL __declspec(naked) SetCursorPosA(int x, int y)
    {
        __asm
       {
          mov  edi, edi
          push ebp
          mov  ebp, esp
          jmp [DLLFunc]
       }
    }
    
    int main()
    {
    	Sleep(2000);
    	HINSTANCE hInst = LoadLibrary(TEXT("user32.dll"));
        DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos") + 5;  
    	SetCursorPosA(0, 0);
    
    	return 0;
    }
    

    Es funktioniert jetzt, die Funktion wird ausgeführt, aber danach Crashed das Programm noch



  • Pingu-Group schrieb:

    ich würd behaupten das, dass Problem is das du bei jmp ein Offset angeben musst und nicht die Adresse die du z.B. von GetProcAddress() bekommts.
    Und das Offset wäre: Ziel-Absprung.

    !!



  • was meinst du mit Ziel- Absprung? Ich verstehe nicht ganz was gemeint ist



  • tester312 schrieb:

    was meinst du mit Ziel- Absprung? Ich verstehe nicht ganz was gemeint ist

    00411113 /E9 D8060000       JMP muh.mainCRTStartup //dieser Jump springt von 0x00411113 nach 0x004117F0 und nicht nach D8060000
    ....
    004117F0 \8BFF              MOV EDI,EDI
    

    Sprich:
    Offset = Ziel - Absprung

    Also musst du das Offset angeben das im "Little-Endian-Format" angegeben ist, was ich auch erst vor ein paar Tagen erfahren hab ;).

    Gruß Pingu



  • danke, ich verstehe wo das Problem liegt aber
    Offset = Ziel - Absprung
    Ziel = DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos") + 5;
    Absprung = DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos");
    Offset = DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos") + 5; - DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos");
    ich denke nicht, dass das so gemeint war?



  • tester312 schrieb:

    danke, ich verstehe wo das Problem liegt aber
    Offset = Ziel - Absprung
    Ziel = DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos") + 5;
    Absprung = DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos");
    Offset = DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos") + 5; - DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos");
    ich denke nicht, dass das so gemeint war?

    Noe nicht ganz.
    Also Ziel ist korrekt, aber Absprung ist ja:
    SetCursorPosA + länge der Opcodes bist jmp [DLLFunc] + 5 für die länge des Opcodes jmp

    Deswegen is bei meinem Bspl.

    Ziel: 004117F0
    Absprung: 00411118

    Offset: D8060000 //Little Endian

    Wenn nicht klar dann schau mal den Thread hier an:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-230718.html

    Gruß Pingu



  • SetCursorPosA + länge der Opcodes bist jmp [DLLFunc] + 5 für die länge des Opcodes jmp

    Absprung = (DWORD)GetProcAddress(hInst, "SetCursorPosA") + opcodes + 5

    was sind die länge der Opcodes?



  • Also entweder kannste ned lesen oder du verstehst due Grundlagen nicht!?

    In beiden Fällen rate ich dir lass es einfach!



  • also als erstes, ein einfachs +5 tuts nicht. das verschiebt den offset um
    5 * sizeof(funcptr) = 20 bytes. zuerst nach char casten

    der offset wird vom folgenden befehl aus gerechnet

    quelle = newfunc + 5 + 5
    ziel = func + 5

    ziel - quelle = func - newfunc - 5

    edianprobleme hatte ich auf meinem intel x86 nicht 😛
    hab aber auch das ganze DWORD reinkopiert also nicht byteweise

    musste aber n bissel ruumprobierenbis das aufs byte genau passt, ober von
    obriger formel sollte man ausgehen. (disassembly im debugmodus > all)

    morgen guck ich nochmal den genauen wert nach



  • helferlein schrieb:

    edianprobleme hatte ich auf meinem intel x86 nicht 😛
    hab aber auch das ganze DWORD reinkopiert also nicht byteweise

    Also beim schreiben in Inline Assembly war des bei mir au keine Problem, aber beim auslesen eines jmp + Offset eines Prozesses, siehe verheriger Link, wusste ich nicht wo der hinspringt wegen dem Little-Endian-Format und kommte somit meine Funktion nicht patchen.

    Gruß Pingu



  • wie gehört es sich denn richtig?



  • helferline ich habe es so gemacht wie du gesagt hast:

    #include <windows.h>
    #include <iostream>
    
    using namespace std;
    
    DWORD DLLFunc;
    BOOL __declspec(naked) SetCursorPosA(int x, int y)
    {
        __asm
       {
          mov  edi, edi
          push ebp
          mov  ebp, esp
          jmp [DLLFunc]
       }
    }
    
    int main()
    {
        Sleep(2000);
        HINSTANCE hInst = LoadLibrary(TEXT("user32.dll"));
    	HINSTANCE hInst2 = GetModuleHandle(0);
        DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos") + (char)5 - (DWORD)GetProcAddress(hInst2, "SetCursorPosA") + (char)5 + (char)5;  
        SetCursorPosA(0, 0);
    
        return 0;
    }
    

    Aber jetzt führt es nichtmal mehr die funktion aus



  • hier nochmal der vorherige code

    #include <windows.h>
    #include <iostream>
    
    using namespace std;
    
    DWORD DLLFunc;
    BOOL __declspec(naked) SetCursorPosA(int x, int y)
    {
        __asm
       {
          mov  edi, edi
          push ebp
          mov  ebp, esp
          jmp [DLLFunc]
       }
    }
    
    int main()
    {
        Sleep(2000);
        HINSTANCE hInst = LoadLibrary(TEXT("user32.dll"));
        DLLFunc = (DWORD)GetProcAddress(hInst, "SetCursorPos") + 5;  
        SetCursorPosA(20, 20);
    	Beep(2000, 200);
    	cout << "lol";
    	Sleep(1000);
        return 0;
    }
    

    Alles funktioniert einwandfrei SetCursorPos wird auch ausgeführt und Beep usw auch, erst bei return 0; crashed es. Darauf zeigt der Debugger:
    00344A78 or byte ptr [edx+34h],0
    wie kann etwas bei return 0 crashen oO



  • man schonmal was von nem debugger gehört -wenn du schon solche hässliche frickelei machst, dann debugg den schrott gefälligst selbst 👎


Anmelden zum Antworten