[Tutorial] Modifying/Using client-internal Functions

12/08/2011 18:51 lolkop#1
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:
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
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:
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
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:
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
12/11/2011 03:25 xFr3aKsTyL3D#2
Deine Tutorials hauen mich jedes mal aufs neue um! Danke dir
12/11/2011 11:26 *Dr.Bob*#3
Quote:
Originally Posted by xFr3aKsTyL3D View Post
Deine Tutorials hauen mich jedes mal aufs neue um! Danke dir
Dem kann ich mich nur anschließen, ist jedes mal nen absoluter Knaller.
Nur blöde wenn man keine Ahnung hat woher du diese zahl hast:

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
12/11/2011 13:42 lolkop#4
naja das finden von client funktionen ist sehr aufwändig und hat in der regel auch viel mit glück zu tun.

das finden von der zoom funktion, war in diesem falle relativ leicht, da es einen floatwert für die kameraposition gibt, welcher hierbei global immer gesetzt wird.

das heist man kann ganz normal den speicher nach einem wert durchsuchen, welcher sich nur durch scrollen ändert.
hat man diesen ersteinmal gefundn, so reicht es ja zu schauen, wo der client diesen denn beim scrollen verändert. sobald man sich ersteinmal in der zoomfunktion befindet, dann nurnoch die conditional jumps beobachten, und schauen welche jumps sich anders verhalten, wenn ich beispielsweise den maximalen zoomwert nach aussen bzw innen erreicht habe =)

Edit:
das selbe gilt für die jumpfunktion :P
12/14/2011 19:27 mikele95123#5
it doesn't work!
12/14/2011 19:48 lolkop#6
the word "work" makes absolutely no sense, if the tutorial just shows some code snipets...