Multi Client [How To]

  • Multiclient Howto
    Einen Multiclient zu erstellen ist recht einfach, trotzdem oftmals unmöglich für Anfänger. Ganz einfach weil sie keinen Ansatzpunkt finden. In diesem Tutorial zeige ich euch wie man einen Multiclient erstellen kann und diese Technik lässt sich auf so ziemlich jedes Game anwenden.



    #Inhalt:
    [-]Voraussetzungen & Programme
    [-]Theorie
    [-]Patching
    [-]Nachwort




    [-]Voraussetzungen & Programme


    Voraussetzungen:

    • Grundlegende Erfahrung im Umgang mit Debuggern
    • Grundlegende ASM Kenntnisse
    • Menschenverstand


    Programme:


    Als Opfer Spiel nehme ich in diesem Beispiel Darkages. Das ist ein 2D MMO. Ihr könnt aber auch andere Spiele nehmen. Aber ich bezieh mich jetzt nur darauf :P Ihr könnt natürlich auch einen anderen Debugger benutzten... aber unter Win gibts keinen besseren als Olly. An die Oldschooler: Yes softice ist besser aber problematisch unter win xp :P





    [-]Theorie


    Um einen Multiclient zu erstellen, müssen wir erstmal wissen, was genau im Programm die Instanzen limitiert. Und das zauberwort heißt hier CreateMutex()


    Auszug aus der MSDN:



    HANDLE WINAPI CreateMutex(
    __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
    __in BOOL bInitialOwner,
    __in_opt LPCTSTR lpName
    );
    CreateMutex befindet sich in der Kernel32.dll / lib. Außerdem nicht wundern , je nachdem ob Unicode oder ANSI kann die Funktion CreateMutexA oder CreateMutexW heißen.
    Außerdem in seltenen Fällen noch CreateProcess:



    BOOL WINAPI CreateProcess(
    __in_opt LPCTSTR lpApplicationName,
    __inout_opt LPTSTR lpCommandLine,
    __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
    __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
    __in BOOL bInheritHandles,
    __in DWORD dwCreationFlags,
    __in_opt LPVOID lpEnvironment,
    __in_opt LPCTSTR lpCurrentDirectory,
    __in LPSTARTUPINFO lpStartupInfo,
    __out LPPROCESS_INFORMATION lpProcessInformation
    );
    Das wichtige bei CreateProcess ist bInheritHandles




    Zitat:
    Zitat von MSDN bInheritHandles [in]


    If this parameter TRUE, each inheritable handle in the calling process is inherited by the new process. If the parameter is FALSE, the handles are not inherited. Note that inherited handles have the same value and access rights as the original handles.



    [-]Patching


    So genug Theorie, jetzt gehts los! Zuerst öffnen wir Darkages.exe in Ollydbg.
    Dann drücken wir STRG+A oder machen einen Rechtsklick ins CPU Fenster und klicken auf Analyze -> Analyze Code. Besser noch wenn ihr das Analyze This! Plugin habt, dann klickt ihr da drauf.


    [Blocked Image: http://img3.imagebanana.com/img/9xkk4ro4/1.png]


    Dann machen wir wieder einen Rechtsklick -> Search for -> All intermodular calls.
    [Blocked Image: http://img3.imagebanana.com/img/cobvlqxw/2.png]


    Nun sehen wir alle API Calls. Leider etwas durcheinander, aber das bekommen wir auch noch hin [Blocked Image: http://www.elitepvpers.de/forum/images/smilies/smile.gif]
    Rechtsklick -> Sort by -> Destination.
    [Blocked Image: http://img3.imagebanana.com/img/bwbrcw3s/3.png]


    So nun müssen wir CreateMutex(W/A) suchen. Da wir wissen das sich die Funktion in der Kernel32 befindet, wird die suche einfach.
    Und wir haben 2 CreateMutexA Funktionen und 3 CreateProcessA Funktionen.
    [Blocked Image: http://img3.imagebanana.com/img/ojbiiafa/4.png]


    Wir doppelklicken nun die erste CreateMutexA Funktionen und kommen dahin:


    [Blocked Image: http://img3.imagebanana.com/img/kqnskxes/5.png]


    Wir sehen nun an welcher stelle CreateMutex gecallt wird.



    00518290 . 6A 00 PUSH 0 ; /MutexName = NULL
    00518292
    . 6A 00 PUSH 0 ; |InitialOwner = FALSE
    00518294
    . 6A 00 PUSH 0 ; |pSecurity = NULL
    00518296
    . FF15 8CD26800 CALL DWORD PTR DS:[<&KERNEL32.CreateMute>; CreateMutexA
    Wir können dort auch sehr schön die CreateMutex Struktur erkennen, wie sie in der MSDN beschrieben wurde.


    Dann gehen wir etwas weiter runter in den Code. Dann sehen wir wie irgendwas verschoben wird.




    0051829C . 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
    0051829F . 8941 04 MOV DWORD PTR DS:[ECX+4],EAX
    005182A2
    . 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
    Besonders als Anfänger, weiß man überhaupt nicht was dort passiert. Das muss man auch nicht unbedingt. Das kommt mit der Zeit, aber schauen wir mal noch ein bisschen tiefer.



    005182A5 . 837A 04 00 CMP DWORD PTR DS:[EDX+4],0
    005182A9
    . 75 0E JNZ SHORT 005182B9
    Dort sehen wir das irgendwas mit 0 verglichen wird, und dann folgt ein JNZ. ( Jump if Not Zero)
    Also springt er nur wenn der Vergleich nicht 0 ist. Es ist also ein Conditional Jump. Es hat eine Bedingung.
    Dann schauen wir wo wir hinspringen.
    [Blocked Image: http://img3.imagebanana.com/img/ua1l3fvu/6.png]


    Wie wir sehen, überspringt er die



    005182B5 . /EB 53 JMP SHORT 0051830A
    005182B7
    . |EB 51 JMP SHORT 0051830A
    Und diese springen dann noch weiter.


    Lange Rede kurzer Sinn, unser Badboy ist das JNZ. Wir wollen das er immer springt (Unconditional Jump).
    Wir klicken also auf das:



    JNZ SHORT 005182B9
    und drücken Leertaste. Wir können aber auch einen Doppelklick machen.
    Dann ändern wir das JNZ in JMP und klicken Assemble.


    [Blocked Image: http://img3.imagebanana.com/img/2ufdd8e/7.png]



    So wir haben es geschafft. Oder doch nicht? Ach stimmt, es gab ja 2 CreateMutex und noch 3 CreateProcess die uns Probleme machen könnte.


    Also minimieren wir das CPU Fenster und gehen nochmal in das "Found Intermodular calls" - Fenster. Dann machen wir einen Doppelklick auf das 2te CreateMutex und landen hier:


    [Blocked Image: http://img3.imagebanana.com/img/uem7fqr/8.png]


    Und was sehen unsere Augen da? Wieder ein JNZ!
    Ein Doppelklick da drauf, JNZ -> in JMP umändern , Assemble klicken und Fertig.


    Aber da waren ja noch die CreateProcess Funktionen. Wir gehen also nochmals in das Intermodular Calls Fenster und machen einen Doppelklick auf das erste CreateProcess. Und wir kommen dahin:
    [Blocked Image: http://img3.imagebanana.com/img/es2gt7o2/9.png]


    Wir erinnern uns, das wichtige war bInheritHandles. Aber es ist hier auf FALSE.




    00535E98 |. 6A 00 PUSH 0 ; |InheritHandles = FALSE
    Probleme würde es nur machen wenn dort PUSH 1 stehen würde. Wenn das der Fall wäre, müssten wir nur einen Doppelklick da drauf machen und aus dem PUSH 1 ein PUSH 0 machen.


    Dann überprüfen wir noch die anderen CreateProcess Funktionen. Aber in unserem Fall, ist überall der bInheritHandles FALSE!


    So nun machen wir einen Rechtsklick -> Copy to executeable -> All modifications.
    [Blocked Image: http://img3.imagebanana.com/img/jrwtyy2j/10.png]


    Copy All!


    [Blocked Image: http://img3.imagebanana.com/img/kdssf8x/11.png]


    Dann machen wir einen Rechtsklick -> Save to file


    [Blocked Image: http://img3.imagebanana.com/img/tzb7n2hs/12.png]


    Und benennen es erstmal Darkages[fix].exe. Nicht das ihr eure Orginal Datei überschreibt und es funktioniert nicht. Dann starten wir Darkages[fix].exe zwei mal . Und es sollten sich auch 2 Clients öffnen.


    Dann könnt ihr euren orginalen Client backupen, und die Darkages[fix].exe ind Darkages.exe umbennen.