Multiclient Howto
Creating a Multiclient is simple, nevertheless impossible for beginners, quite simply because they see no point.
In this tutorial im going to show you how to create an Multiclient with a technic which is useable for the most games.
#content:
[-]Prerequisites & Programms
[-]Theory
[-]Patching
[-]Conclusion
[-]Prerequisites & Programms
Prerequisites:- Basics in using a Debugger
- Basic Knowledge in ASM
- Your Brain
Programms:
As sacrifice, i choose Dark Ages (2D MMO). But you can also choose any game else. Of course you can also choose another Debugger, but Olly is the best one on XP. To the Oldschoolers: Yes SoftICE is better but troubling on XP :P
[-]Theory
To create a Multiclient, we have to know what limit's our Instances. They Magic Word is: CreateMutex()
excerpts from MSDN:
Quote:
HANDLE WINAPI CreateMutex(
__in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
__in BOOL bInitialOwner,
__in_opt LPCTSTR lpName
);
|
CreateMutex() Can be found in the Kernel32.dll / lib. Moreover dont wonder: Depending on Unicode or ANSI the Function can also be called CreateMutexA or CreateMutexW.
In rare cases also: CreateProcess()
Quote:
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
);
|
The important thing here is:
bInheritHandles
Quote:
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, enough Theroy. Lets get started! At first, we open Darkages in Ollydbg.exe. Then we Press CTRL+A or rightclick into the CPU window and click "Analyze -> Analyze Code". Best case is, if you have the Analyze This! Plugin, click there.
Then we rightclick again: Search for -> All intermodular calls.
Now we see all API calls. unfortunately somewhat confused, but we'll get it yet

Rightclick -> Sort by -> Destination
Now we've to find CreateMutex(A/W). Cuz we know the Function is located in the Kernel32, the search is going to be easy.
Tadaaaa we have 2 CreateMutexA() and 3 CreateProcessA() Function's.
We double-click the CreateMutex Function and come out here:
Now we can see, where CreateMutex is called from
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:[<&K
Also, we obviously can see the Structure of CreateMutex, how its defined in the MSDN.
Then we take a look at the code below and see, how something is moved.
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]
Especially as beginner, you don't have a clue what's happnin there. There's no need yet, it'll come with the time. Now let's look a bit deeper into the code.
PHP Code:
005182A5 . 837A 04 00 CMP DWORD PTR DS:[EDX+4],0
005182A9 . 75 0E JNZ SHORT 005182B9
There, we can see that something is compared with 0. A JNZ follows (
Jump if
not
Zero). That means, it just jumps, if the comparison is not 0. It's an Conditional Jump: it has a condition.
Now we look where we are jumping to.
We can see: It's overjumping the
PHP Code:
005182B5 . /EB 53 JMP SHORT 0051830A
005182B7 . |EB 51 JMP SHORT 0051830A
And those are continueing to jump.
Long story short sense: The Badboy is the JNZ. We want that he's always jump.
So we click the
PHP Code:
JNZ SHORT 005182B9
And press Space. Then we change from JNZ to JMP and press Assemble
So, we finished? Ah yes, there were 2 CreateMutex and 3 CreateProcess which can bring us in trouble.
We minimize the CPU window and go into the "Found Intermodular calls" - Window. We double-click the 2nd CreateMutex and come out here:
What are our eyes seeing?!

Another JNZ !
double-click -> JNZ -> JMP -> Assemble
We remember the CreateProcess Function. So we go again to the "Found Intermodular calls" - Window and doubleclick the first CreateProcess.
We see:
We remember, the importest thing was bInheritHandle. Its false here!
PHP Code:
00535E98 |. 6A 00 PUSH 0 ; |InheritHandles = FALSE
We just would've problems with this, if the PUSH 0 is a PUSH 1. If this would be the case, we would've to change the PUSH 1 into a PUSH 0.
Now we check the other CreateProcess Functions, but in our case at every Function bInheritHandles is false !
Now we rightlick -> Copy to executeable -> All modifications.
Copy All!
Rightlick -> Save to file
We rename it to Darkages[fix].exe, because it shouldn't overwrite our already existing executable. Otherwise maybe it won't work. Now start it 2 times.
If everything is working you can rename the fix into Darkages.exe. But backup your original exe before !
[-]Nachwort
The latter has become somewhat more detail than I thought

You will encounter quite so all the games on CreateMutex and CreateProcess
suche. Now you know how to defeat it.
It's Basic. I hope you understood it
--------------------------------------------------------------
Ich hoffe das geht so.. ich mit meinem schlechten Schulenglisch xD