while analyzing the client with your favorite debugger, you might run into some client functions...
especially if you're trying to break/bypass some special stuff, you'll allways have to find the client function, which handles it.
if you wanna break the swearfilter (badword-filter) in the client, you'll allways start with searching for the ChatInputHandler function =)
in this tutorial, i'm not going to explain, how to trace through the client, to find such things. if you're intrested in learning the basics about rever engineering, you should google for tutorials...
a basic binary snipet, to find the ChatInputHandler function looks like this for 4Story:
once you've found that function, you should set a breakpoint on that function, and trace through it with a "bad word" and a "good" one of the same length.
you can simply make olly log tracings to files. this will make it more easy to compare both logs later.
comparing those logs, you'll find a place, where both codes run into different directions. as an example, here's my comparisson of log files:
[Only registered and activated users can see links. Click Here To Register...]
looks like that jge only jumps, if the text gets filtered. so all we have to do, to disable the badword filter, is to never make that jge jump (simply nop it)
this way, we can start playing around a little more with the client.
since i'm not really playin the game, i don't know, which limitations could be more interesting.
but here are some examples for client limitations, which can be easily desabled by a few nops:
well so far, i only explained, how to modify such functions.
since i removed the jump limit, i'll take the jump function as example.
if we wanna jump ingame, we'd have to send a [space] key to our game...
there's an even better way to perform a jump, by simply calling the jump function itself =)
if you're setting a breakpoint on the entry point of the jump function, and trace it back, u'll see something like this:
some of you might think, that we have to inject dlls to use inline functions. this is simply wrong. everything we need for doing stuff like this, is given us by the winapis.
all we need to do, is to allocate some memory in the client, fill it with our code logic, and run it as a new thread.
here's a simple autoit example for using the Jump function in the eg client:
especially if you're trying to break/bypass some special stuff, you'll allways have to find the client function, which handles it.
if you wanna break the swearfilter (badword-filter) in the client, you'll allways start with searching for the ChatInputHandler function =)
in this tutorial, i'm not going to explain, how to trace through the client, to find such things. if you're intrested in learning the basics about rever engineering, you should google for tutorials...
a basic binary snipet, to find the ChatInputHandler function looks like this for 4Story:
Code:
64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 24 55 56 8B F1 33 ED 89 6C 24 18
you can simply make olly log tracings to files. this will make it more easy to compare both logs later.
comparing those logs, you'll find a place, where both codes run into different directions. as an example, here's my comparisson of log files:
[Only registered and activated users can see links. Click Here To Register...]
looks like that jge only jumps, if the text gets filtered. so all we have to do, to disable the badword filter, is to never make that jge jump (simply nop it)
this way, we can start playing around a little more with the client.
since i'm not really playin the game, i don't know, which limitations could be more interesting.
but here are some examples for client limitations, which can be easily desabled by a few nops:
well so far, i only explained, how to modify such functions.
since i removed the jump limit, i'll take the jump function as example.
if we wanna jump ingame, we'd have to send a [space] key to our game...
there's an even better way to perform a jump, by simply calling the jump function itself =)
if you're setting a breakpoint on the entry point of the jump function, and trace it back, u'll see something like this:
Code:
00514043 |. 8B8E A80A0000 MOV ECX,DWORD PTR DS:[ESI+AA8] <--- ESI contains [MainCharBase] 00514049 |. 8B01 MOV EAX,DWORD PTR DS:[ECX] 0051404B |. FF90 50020000 CALL DWORD PTR DS:[EAX+250] <--- Calls the JumpFunction
all we need to do, is to allocate some memory in the client, fill it with our code logic, and run it as a new thread.
here's a simple autoit example for using the Jump function in the eg client:
Code:
;~ Jump:
;~ 60 PUSHAD Save all registers
;~ 8B35 D0116F00 MOV ESI,DWORD PTR DS:[6F11D0] Set ESI to [MainCharBase]
;~ 8B8E A80A0000 MOV ECX,DWORD PTR DS:[ESI+AA8] Client code
;~ B8 E0C35300 MOV EAX,TClient.0053C3E0 Move the Jump function to eax
;~ FFD0 CALL EAX Call the Jump function
;~ 61 POPAD Restore the original registers
;~ C3 RETN Return to the main programm
$mid = OpenProcess(ProcessExists('TClient.exe'))
$codeSection = VirtualAllocEx($mid)
WriteProcessMemory($mid, $codeSection, '608B35D0116F008B8EA80A0000B8E0C35300FFD061C3')
$thread = CreateRemoteThread($mid, $codeSection)
WaitForSingleObject($thread)
VirtualFreeEx($mid, $codeSection)
CloseHandle($mid)
Func OpenProcess($pid)
Local $mid = DllCall('kernel32.dll', 'int', 'OpenProcess', 'int', 0x1F0FFF, 'int', 1, 'int', $pid)
Return $mid[0]
EndFunc
Func WriteProcessMemory($process_hwnd, $adress, $data, $type = 'binary')
Local $struct, $i
If $type = 'binary' Then
Local $struct = DllStructCreate('byte[' & BinaryLen('0x' & $data) & ']')
For $i = DllStructGetSize($struct) To 1 Step -1
DllStructSetData($struct, 1, BinaryMid('0x' & $data, $i, 1), $i)
Next
ElseIf $type = 'string' Then
$struct = DllStructCreate('char['&StringLen($data)+1&']')
For $i = 1 To StringLen($data)
DllStructSetData($struct, 1, StringMid($data, $i, 1), $i)
Next
Else
$struct = DllStructCreate($type)
DllStructSetData($struct, 1, $data)
EndIf
DllCall('kernel32.dll', 'int', 'WriteProcessMemory', 'int', $process_hwnd, 'int', $adress, 'int', DllStructGetPtr($struct), 'int', DllStructGetSize($struct), 'int', 0)
EndFunc
Func CloseHandle($hwnd)
DllCall('kernel32.dll', 'int', 'CloseHandle', 'int', $hwnd)
EndFunc
Func VirtualAllocEx($process_hwnd, $size = 1024)
Local $adress = DllCall('kernel32.dll', 'int', 'VirtualAllocEx', 'int', $process_hwnd, 'ptr', 0, 'int', $size, 'int', 0x1000, 'int', 0x40)
Return $adress[0]
EndFunc
Func VirtualFreeEx($process_hwnd, $adress)
DllCall('kernel32.dll', 'ptr', 'VirtualFreeEx', 'hwnd', $process_hwnd, 'int', $adress, 'int', 0, 'int', 0x8000)
EndFunc
Func CreateRemoteThread($process_hwnd, $adress)
Local $thread = DllCall('kernel32.dll', 'int', 'CreateRemoteThread', 'int', $process_hwnd, 'int', 0, 'int', 0, 'int', $adress, 'ptr', 0, 'int', 0, 'int', 0)
Return $thread[0]
EndFunc
Func WaitForSingleObject($thread)
Do
$return = DllCall('kernel32.dll', 'int', 'WaitForSingleObject', 'int', $thread, 'int', 50)
Until $return[0] <> 258
EndFunc