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.
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:
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.Quote:
HANDLE WINAPI CreateMutex(
__in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
__in BOOL bInitialOwner,
__in_opt LPCTSTR lpName
);
Außerdem in seltenen Fällen noch CreateProcess:
Das wichtige bei CreateProcess ist bInheritHandlesQuote:
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
);
Quote:
Originally Posted by MSDNbInheritHandles [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.
Dann machen wir wieder einen Rechtsklick -> Search for -> All intermodular calls.
Nun sehen wir alle API Calls. Leider etwas durcheinander, aber das bekommen wir auch noch hin
Rechtsklick -> Sort by -> Destination.
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.
Wir doppelklicken nun die erste CreateMutexA Funktionen und kommen dahin:
Wir sehen nun an welcher stelle CreateMutex gecallt wird.
PHP Code:
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
Dann gehen wir etwas weiter runter in den Code. Dann sehen wir wie irgendwas verschoben wird.
PHP Code:
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]
PHP Code:
005182A5 . 837A 04 00 CMP DWORD PTR DS:[EDX+4],0
005182A9 . 75 0E JNZ SHORT 005182B9
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.
Wie wir sehen, überspringt er die
PHP Code:
005182B5 . /EB 53 JMP SHORT 0051830A
005182B7 . |EB 51 JMP SHORT 0051830A
Lange Rede kurzer Sinn, unser Badboy ist das JNZ. Wir wollen das er immer springt (Unconditional Jump).
Wir klicken also auf das:
PHP Code:
JNZ SHORT 005182B9
Dann ändern wir das JNZ in JMP und klicken Assemble.
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:
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:
Wir erinnern uns, das wichtige war bInheritHandles. Aber es ist hier auf FALSE.
PHP Code:
00535E98 |. 6A 00 PUSH 0 ; |InheritHandles = FALSE
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.
Copy All!
Dann machen wir einen Rechtsklick -> Save to file
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.
[-]Nachwort
Puh. Ist ja doch etwas ausführlicher geworden, als ich mir gedacht habe
Ihr werdet in so ziemlich allen Spielen auf CreateMutex und CreateProcess stoßen. Nun wisst ihr auch wie man diese umschreibt, damit man mehrere Clients starten kann.
Probleme auf die ihr stoßen könnt ist das wenn ihr auf CreateMutex doppelklickt und an diese Stelle springt auf den ersten Blick kein JNZ findet. Versucht den Code so gut wie möglich zu verstehen, manchmal ist es etwas weiter unten im Code Also sucht schön *g*
Außerdem kann es sein das der Client CRC Checks macht. Dafür gibts aber ein schönes Plugin für PEiD. Damit könnt ihr die neue CRC vom patched client mit der alten überschreiben.
Ist ansich ziemlich Basic, ich hoffe es war verständlich :P