Что нового

[Сеть, интернет] Аналог WPE PRO на Autoit

botd

Новичок
Сообщения
4
Репутация
1
Прошу вашей помощи.
Задача такая – есть клиент игры. Он посылает серверу пакеты. Нужно написать программу, которая от имени клиента будет слать пакеты серверу. Именно так работает сниффер WPE PRO.
Разумеется, перед тем как написать на форум, я погуглил возможные решения. Вот они:
1. TCPSend http://autoit-script.ru/autoit3_docs/functions/TCPSend.htm - т.е. устанавливаем новое соединение, и начинаем общение с сервером. Фактически придется писать новый клиент. Не пойдет. А если достать указатель на сокет? Увы, как сказали в этой теме: http://autoit-script.ru/index.php?topic=14216.0 «Дескриптор сокета валиден только для процесса, в котором его получили. Поэтому придется инжектить код в целевой процесс игры чтобы работать в контексте ее процесса.» Если это так, то этот вариант не пойдет.
2. Воспользоваться библиотекой Winpcap. Поставить на прослушку сеть и фильтровать пакеты. Но это не то, мне нужно отсылать пакеты, а не перехватывать…
3. Инжект библиотеки Ws2_32.dll. Хороший пример тут: http://www.autoitscript.com/forum/topic/136339-hooking-functions-with-autoit/
4. Инжект библиотеки Kernel32.dll. Тему нашел тут: http://www.cheatsbrasil.org/local/autoit/22274-babyloves-funcoes-para-wyd-intermediario.html
Самыми перспективными мне показались инжекты.
Проанализировав код 4-ого варианта, пришел к выводу, что возможно там привязка к какой-то конкретной игре. Во всяком случае, когда я запустил этот скрипт и попробовал отослать свой пакет, клиент вылетел (а при отсылке через WPE PRO все работает). Если кого заинтересует, могу привести листинг своего скрипта.
Третий вариант не зарубил игры, и даже что-то распечатал в консоли. Допустим, что действительно перехвачен пакет от игры (хотя меня берут сомнения – что-то слишком часто клиент отправляет пакеты, WPE PRO показывает, что они идут реже). Именно перехвачен, а не просто прочитан, как это было с Winpcap. Т.е. теоритически я могу подменить содержимое. Замечательная возможность, но она сейчас не требуется. Нужно отправить новый пакет от имени игры. Вопрос – как это сделать, основываясь на инжекте? Просто вызвать функцию хука? Или? Короче, привожу листинг:
Код:
#include "Hooking.au3"
;===================>Global Variables
Global $hHook, $hProc
Global $pString[2] = [0, 0] ;the first element holds the address and the second the length, so its easier to call the _DelString() Function
Global $sProcessName = "Client.exe" ;our target process
;===========>
SetPrivilege("SeDebugPrivilege", 1) ;too trivial
$lpMsgBoxA = _WinAPI_GetProcAddress(_WinAPI_GetModuleHandle("Ws2_32.dll"), "send") ;we are reading the address of MessageBoxA in the RAM
$callback = DllCallbackRegister("myHookFunc", "none", "dword") ;we are registering the callback function
If @error Then
	MsgBox(16, "ERROR", "Couldn't initialize Callback")
	Exit
EndIf
$ptr = DllCallbackGetPtr($callback)
_VirtualProtect(Number($ptr), 94) ;we have to unprotect the Callbackfunction
$hProc = _OpenProcess($sProcessName) ;we have to open the process
$hHook = _SetHook(number($lpMsgBoxA), 5, Number($ptr), "int;int;int;int", $hProc) ;we are going to hook the MessageBoxA-Function
Do
	Sleep(1000)
until NOT ProcessExists($sProcessName) ;waiting

Func myHookFunc($iParam) ;=>our HookFunction
	If $pString[0] <> 0 Then _DelString($pString[0], $pString[1], $hProc) ;free the old string
	_GetParameter($iParam, $hHook, $hProc) ;get the parameter from the stack
	ConsoleWrite("================NEW PAKET WILL BE SENDED==========" & @crlf)
	For $i = 2 To 5
		ConsoleWrite($i & ". Argument is " & Number(DllStructgetdata($hHook[5], $i)) & @crlf)
	next
	;==============>String auslesen
	$myString = Hex(DllStructgetdata($hHook[5], 3))
	Consolewrite("Gesendet wird: " & $myString &@crlf)
	;===================>
	_SetParameter($iParam, $hHook, $hProc) ;and write it ;)
	return ;works much better with return
EndFunc


Консоль показывает:
Код:
================NEW PAKET WILL BE SENDED==========
2. Argument is 1192
3. Argument is 154761420
4. Argument is 28
5. Argument is 0
Gesendet wird: 00000000093978CC
Первый аргумент – это soket id.
Второй – отсылаемый пакет (числовое значение)
Третий – размер пакета (мое предположение)
Четвертый – флаг MSG_OOB
Gesendet wird – это шестнадцатеричное представление пакета.
Если я правильно понимаю, то iParam – это параметры, которые передает клиент игры при вызове метода send. Как их формировать? Я даже посмотреть не могу, что там – сразу выкидывает, как только начинаю совершать действия над этой переменной.
В общем нужен пример вызова send через этот хук. Желательно преобразовать пакет из строки, как в WPE PRO (пример пакета в строковом виде: 'AB AC CB E5 50 5A BD B9 0C 00 00 00 00 00 00 00', размер пакета – 16)

Дополнение:
Обнаружил, что клиент вылетает независимо от того, работаю я с iParam или нет. По всей видимости дело в том, что при завершении скрипта надо деинсталлировать хук. Добавил
Код:
_UninstallHook($hHook, $hProc)

И вылеты клиента прекратились. Само значение iParam – это какое-то число (например, 278986220), которое меняется при перезаходе в игру, но постоянно в рамках одной сессии. Следовательно, к отсылке пакета iParam не имеет никакого значения.
Попробовал вызвать myHookFunc($param) и принудительно изменить память длл, поставив туда записанные значения:
Код:
DllStructSetData($hHook[5], 3, 335807180) ; добавляем свое значение пакета
DllStructSetData($hHook[5], 4, 16) ; меняем размер пакета на свой

Консоль показала, что данные добавились со смешением… Т.е.
Код:
DllStructgetdata($hHook[5], 3)

Вернуло не 335807180 как я ожидал…
«хотя меня берут сомнения – что-то слишком часто клиент отправляет пакеты, WPE PRO показывает, что они идут реже»
- после деинсталляции хука сомнения исчезли – пакеты идут с нормальной частотой. Кстати, насчет уборки мусора за собой – наверное надо вызвать перед выходом _FreeOpenProcessHandle ($hProcess, $lpHandle)? Но не знаю, откуда брать $lpHandle. Прикладываю файл Hooking.au3 может кто-нибудь подскажет как правильно вызвать функцию в моем примере. Подозреваю, что _FreeOpenProcessHandle ($hProcess, $lpMsgBoxA) но боюсь ошибиться.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Re: [Сеть, интернет] [Сеть, интернет] [Сеть, интернет] Аналог WPE PRO на Autoit

botd [?]
наверное надо вызвать перед выходом _FreeOpenProcessHandle ...
Функция _UninstallHook это делает. Видимо достаточно только ее.

Тема интересная, буду следить за вашими находками.

Пока я понял так, вы переделываете функцию send библиотеки Ws2_32.dll что бы сперва данные были переданы вашей функции myHookFunc, в которой можно поменять то что отсылается.
 
Автор
B

botd

Новичок
Сообщения
4
Репутация
1
[Сеть, интернет] Re: [Сеть, интернет] [Сеть, интернет] [Сеть, интернет] Аналог WPE PRO на Autoit

inververs сказал(а):
Функция _UninstallHook это делает. Видимо достаточно только ее.
Спасибо, да посмотрел _UninstallHook там есть вызов. Одной проблемой меньше)
inververs сказал(а):
Пока я понял так, вы переделываете функцию send библиотеки Ws2_32.dll что бы сперва данные были переданы вашей функции myHookFunc, в которой можно поменять то что отсылается.
Да, одна из возможностей WPE – это фильтры. Т.е. клиент отправляет серверу пакет, WPE этот пакет изменяет и отправляет дальше серверу. И делает это он, как я понял, как раз через изменение функции send библиотеки Ws2_32.dll (хотя возможно ошибаюсь). Но сейчас передо мной стоит несколько другая задача – как сделать так, чтобы прямо из скрипта можно было отправить пакет. Т.е. не клиент вызывал send, а скрипт обращался к Ws2_32.dll и вызывал send от имени клиента. Для чего этого нужно и в чем отличие от просто модификации пакета? Например, допустим, мне известен пакет покупки предмета в игре. Я хочу купить 100 таких предметов. Запускаю скрипт и он сто раз отправляет этот пакет от имени клиента. При этом в игре я никаких действий не совершаю. А модификация – например, в пакете я нахожу id предмета (ну возьмем яблоко). В скрипте пишу код – если в пакете есть id яблока, то заменить его на id груши. Теперь, когда в игре я покупаю яблоко при работающем скрипте, то вместо него все время будут покупаться груши)
Как видите, модификация пакета и отправка нового пакета – несколько разные задачи. Пока никак не могу понять, что же надо изменить при самостоятельном вызове функции myHookFunc из скрипта, чтобы пакет отправился…
Дальнейшие находки: обнаружил, что собственно данные в памяти меняются и так, без всякого вызова DllStructSetData(). Т.е. при повторном вызове myHookFunc из скрипта сокет изменяется с 1188 на 1184 и переместился со 2-ого на 4-ое место. Остальные данные тоже смещаются.
Перехват пакета от игры:
Код:
================NEW PAKET WILL BE SENDED==========
1. Argument is 24839990
2. Argument is 1188
3. Argument is 352760148
4. Argument is 45
5. Argument is 0
iParam: 321584620
Gesendet wird: 352760148
Проход
Отправка того же пакета из скрипта:
Код:
================NEW PAKET WILL BE SENDED==========
1. Argument is 0
2. Argument is 321584960
3. Argument is 24840376
4. Argument is 1184
5. Argument is 120
iParam: 321584620
Модификация...
Gesendet wird: 335807180
Так же обнаружил, что применение DllStructSetData() вызывает стабильный крах игры (оказывается, я изменял флаг modif после вызова функции, а не до). Пока закомментировал флаг. Вот текущий код скрипта:
Код:
#include "Hooking.au3"
;===================>Global Variables
Global $hHook, $hProc
Global $pString[2] = [0, 0] ;the first element holds the address and the second the length, so its easier to call the _DelString() Function
Global $sProcessName = "Client.exe" ;our target process
Global $param1 = 0;
Global $soketClient = 0;
Global $sizePacket = 0;
Global $MSG_OOB = 0;
Global $modif = 0
Global $param;
;===========>
SetPrivilege("SeDebugPrivilege", 1) ;too trivial
$lpMsgBoxA = _WinAPI_GetProcAddress(_WinAPI_GetModuleHandle("Ws2_32.dll"), "send") ;we are reading the address of MessageBoxA in the RAM
$callback = DllCallbackRegister("myHookFunc", "none", "dword") ;we are registering the callback function
If @error Then
	MsgBox(16, "ERROR", "Couldn't initialize Callback")
	Exit
EndIf
$ptr = DllCallbackGetPtr($callback)
_VirtualProtect(Number($ptr), 94) ;we have to unprotect the Callbackfunction
$hProc = _OpenProcess($sProcessName) ;we have to open the process
$hHook = _SetHook(number($lpMsgBoxA), 5, Number($ptr), "int;int;int;int", $hProc) ;we are going to hook the MessageBoxA-Function
;Do
;	Sleep(1000)
;until NOT ProcessExists($sProcessName) ;waiting

; Ждем инициализацию сокета. Как только от клиента пришел пакет, завершаем цикл.
While Number($soketClient)<1
	Sleep(1000)
	Consolewrite("Проход " & @crlf)
WEnd

;попытка отправить пакет на открытый сокет. Ошибка.
;$paket = 'B9 A9 CB E1 50 5A BD B9 0C 00 00 00 00 00 00 00'
;_TCPSend($soketClient, $paket, $MSG_OOB)

; Вызываем функцию отправки.
; $param - глобальная переменная. Значение заностися при первом перехвате пакета от игры
; $modif - флаг, указывающий на то, что текущий пакет отправлен от Autoit, а не от клиента игры.

;$modif = 1
myHookFunc($param)

_UninstallHook($hHook, $hProc)

Func myHookFunc($iParam) ;=>our HookFunction
	If $pString[0] <> 0 Then _DelString($pString[0], $pString[1], $hProc) ;free the old string
	_GetParameter($iParam, $hHook, $hProc) ;get the parameter from the stack
	ConsoleWrite("================NEW PAKET WILL BE SENDED==========" & @crlf)
	For $i = 1 To 5
		ConsoleWrite($i & ". Argument is " & Number(DllStructgetdata($hHook[5], $i)) & @crlf)
	next
	Consolewrite("iParam: " & $iParam &@crlf)
	;==============>String auslesen
;	$myString = _ReadString(DllStructgetdata($hHook[5], 3), $hproc)
	$param = $iParam
	If $modif>0 Then
;		DllStructSetData($hHook[5], 1, $param1)
;		DllStructSetData($hHook[5], 2, 1188)
		DllStructSetData($hHook[5], 3, 335807180)
		DllStructSetData($hHook[5], 4, 16)
		Consolewrite("Модификация..." & @crlf)
;		DllStructSetData($hHook[5], 5, 0)
		$modif = 0
	EndIf
	$param1 = DllStructgetdata($hHook[5], 1)
	$soketClient = DllStructgetdata($hHook[5], 2)
	$sizePacket = DllStructgetdata($hHook[5], 4)
	$MSG_OOB = DllStructgetdata($hHook[5], 5)
	$myString = String(DllStructgetdata($hHook[5], 3))
	Consolewrite("Gesendet wird: " & $myString &@crlf)

	;===================>
	_SetParameter($iParam, $hHook, $hProc) ;and write it ;)
	return ;works much better with return
EndFunc

Func _TCPSend($Sock, $sData, $iFlag)
    Local $DataBuffer = DllStructCreate("char[" & StringLen($sData)+2 & "]")
    DllStructSetData($DataBuffer, 1, $sData)

    $Ret = DllCall("Ws2_32.dll", "int", "send", "ptr", $Sock, "ptr", DllStructGetPtr($DataBuffer), "int", DllStructGetSize($DataBuffer)-1, "int", $iFlag)
    If $Ret[0] = -1 Then Exit MsgBox(16,"Error",_WinAPI_GetLastErrorMessage())
EndFunc
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Re: [Сеть, интернет] [Сеть, интернет] [Сеть, интернет] Аналог WPE PRO на Autoit

botd [?]
ак сделать так, чтобы прямо из скрипта можно было отправить пакет
Тогда кажется у вас все сделано. Если код библиотеки рабочий и делает то что нужно, вам видимо нужно просто вызывать _SetParameter($iParam, $hHook, $hProc) с правильными параметрами.
 
Автор
B

botd

Новичок
Сообщения
4
Репутация
1
Re: [Сеть, интернет] [Сеть, интернет] [Сеть, интернет] Аналог WPE PRO на Autoit

inververs сказал(а):
Если код библиотеки рабочий и делает то что нужно, вам видимо нужно просто вызывать _SetParameter($iParam, $hHook, $hProc) с правильными параметрами.
Код библиотеки рабочий… Во всяком случае она читает пакеты, это факт. Идея вызова _SetParameter() хороша, но как узнать правильные параметры?
Решил отследить, как меняются все три параметра. $iParam представляет собой постоянную величину, он не меняется от пакета к пакету. Его можно считать один раз и успокоится.
$hHook – это массив из семи ячеек. При вызове _ArrayDisplay($hHook) получил вот такие значения:
Код:
hHook[0]: 0x075D0000
hHook[1]: 49
hHook[2]: 0x07A70000
hHook[3]: ‹яU‹м
hHook[4]: 5
hHook[5]: 
hHook[6]: 1975807745
hHook[0] и hHook[2] постоянно меняются от пакета к пакету. hHook[5] представляет собой не поймешь что. Остальные ячейки неизменны.
Что касается $hProc – то по идее это дескриптор процесса, т.е. неизменная величина.
Итак, получается, что каким-то образом надо узнать алгоритм формирования hHook. Что собой представляет hHook я пока плохо понимаю.
 
Автор
B

botd

Новичок
Сообщения
4
Репутация
1
Посмотрел внимательно на функцию _SetParameter (оригинал смотреть в Hooking.au3)
Код:
Func _SetParameter($iEsp, $hHook, $hProcess) 
	$iEsp += 8 
	$myStruct = DllStructCreate("byte[" & DllStructGetSize($hHook[5]) & "]", DllStructGetPtr($hHook[5]))
	_MemoryWrite($iEsp, $hProcess, DllStructGetData($myStruct, 1), "byte[" & DllStructGetSize($myStruct) & "]")
EndFunc

Что она делает? Создает новую структуру путем копирования структуры $hHook[5]. Но что представляет собой $hHook[5]? В коде функции _SetHook() мы видим, что это
Код:
$paramStruct = DllStructCreate("dword;" & $sParams)

где
Код:
$sParams  = "int;int;int;int"

Таким образом, функция _SetParameter() просто записывает некоторую структуру в память игры. Следовательно, что мешает мне создать свою структуру? И передать её в _SetParameter()
Казалось бы, ничего. Сказано – сделано, написал новую функцию
Код:
Func _SendPacket($iEsp, $hProcess, $Packet, $sPacket) ;Отправляет пакет
	$paramStruct = DllStructCreate("dword;int;int;int;int") ;создаем структуру для пакета
	DllStructSetData($paramStruct, 1, $param1) ;неизвестный параметр
	DllStructSetData($paramStruct, 2, $soketClient) ;сокет
	DllStructSetData($paramStruct, 3, $Packet) ;пакет
	DllStructSetData($paramStruct, 4, $sPacket) ;размер пакета
	DllStructSetData($paramStruct, 5, $MSG_OOB) ;0
	$iEsp += 8 
	$myStruct = DllStructCreate("byte[" & DllStructGetSize($paramStruct) & "]", DllStructGetPtr($paramStruct))
	_MemoryWrite($iEsp, $hProcess, DllStructGetData($myStruct, 1), "byte[" & DllStructGetSize($myStruct) & "]")
EndFunc

Все параметры получил путем считывания из myHookFunc. В результате вызова _SendPacket() игра сразу вылетела. Есть предположения, где ошибка? Правильно ли я рассуждал?
Вообще я думаю, что сам перехват данных мне не нужен. Мне нужен вызов функции Send библиотеки "Ws2_32.dll" от имени игры. Например, в этой теме http://allcheats.ru/t206375/ есть упоминание, что можно вызывать функции самой игры из Autoit. Но как сделать это применительно к моей функции увы не пойму…
 

Nelsy

Знающий
Сообщения
35
Репутация
8
Что касается игр то в них заложены функции "общения" с сервером. К примеру, если надо отправить персонажа кликнув по земле, то игра вызывает по твоему клику функцию которая собирает данные в пакет, типа координаты, тому подобное и вызывает функцию отправления пакета передавая ей данные.
В таком случае мы ставим хук на левый клик мыши, и смотрим что происходит в клиенте игры после ее нажатия, а происходит там выше описанный процесс =)
В общем проанализировав данный процесс ты можешь оставить сборку пакета за скриптом аутоит, а отправку за клиентом вызвав нужную функцию отправки пакета и передав ей все собранные данные.
Вообще тема конечно интересная, но тут попахивает больше реверс инженерингом а не коддингом на аутоите, ибо времени больше уйдет на первое чем на второе.

Код:
Func sendPacket($packet, $packetSize, $PROCESS_ID)
	;Declare local variables
	Local $pRemoteThread, $vBuffer, $loop, $result, $OPcode, $processHandle, $packetAddress
	
	;Open process for given processId
	$processHandle = $PROCESS_INFORMATION[1]
	
	;Allocate memory for the OpCode and retrieve address for this
	$functionAddress = DllCall($KERNEL32, 'int', 'VirtualAllocEx', 'int', $processHandle, 'ptr', 0, 'int', 0x46, 'int', 0x1000, 'int', 0x40)
	
	;Allocate memory for the packet to be sent and retrieve the address for this
	$packetAddress = DllCall($KERNEL32, 'int', 'VirtualAllocEx', 'int', $processHandle, 'ptr', 0, 'int', $packetSize, 'int', 0x1000, 'int', 0x40)
	
	;Construct the OpCode for calling the 'SendPacket' function
	$OPcode &= '60'								;PUSHAD
	$OPcode &= 'B8'&_hex($SENDPACKETADDRESS)	;MOV	 EAX, sendPacketAddress
	$OPcode &= '8B0D'&_hex($REALBASEADDRESS)	;MOV     ECX, DWORD PTR [revBaseAddress]
	$OPcode &= '8B4920'							;MOV     ECX, DWORD PTR [ECX+20]
	$OPcode &= 'BF'&_hex($packetAddress[0])		;MOV     EDI, packetAddress	//src pointer
	$OPcode &= '6A'&_hex($packetSize,2)			;PUSH    packetSize		//size
	$OPcode &= '57'								;PUSH    EDI
	$OPcode &= 'FFD0'							;CALL    EAX
	$OPcode &= '61'								;POPAD
	$OPcode &= 'C3'								;RET		
	
	;Put the OpCode into a struct for later memory writing
	$vBuffer = DllStructCreate('byte[' & StringLen($OPcode) / 2 & ']')
	For $loop = 1 To DllStructGetSize($vBuffer)
		DllStructSetData($vBuffer, 1, Dec(StringMid($OPcode, ($loop - 1) * 2 + 1, 2)), $loop)
	Next
	
	;Write the OpCode to previously allocated memory
	DllCall($KERNEL32, 'int', 'WriteProcessMemory', 'int', $processHandle, 'int', $functionAddress[0], 'int', DllStructGetPtr($vBuffer), 'int', DllStructGetSize($vBuffer), 'int', 0)
		
	;Put the packet into a struct for later memory writing
	$vBuffer = DllStructCreate('byte[' & StringLen($packet) / 2 & ']')
	For $loop = 1 To DllStructGetSize($vBuffer)
		DllStructSetData($vBuffer, 1, Dec(StringMid($packet, ($loop - 1) * 2 + 1, 2)), $loop)
	Next
	
	;Write the packet to previously allocated memory
	DllCall($KERNEL32, 'int', 'WriteProcessMemory', 'int', $processHandle, 'int', $packetAddress[0], 'int', DllStructGetPtr($vBuffer), 'int', DllStructGetSize($vBuffer), 'int', 0)
		
	;Create a remote thread in order to run the OpCode
	$hRemoteThread = DllCall($KERNEL32, 'int', 'CreateRemoteThread', 'int', $processHandle, 'int', 0, 'int', 0, 'int', $functionAddress[0], 'ptr', 0, 'int', 0, 'int', 0)
	
	;Wait for the remote thread to finish
	Do
		$result = DllCall('kernel32.dll', 'int', 'WaitForSingleObject', 'int', $hRemoteThread[0], 'int', 50)
	Until $result[0] <> 258
	
	;Close the handle to the previously created remote thread
	DllCall($KERNEL32, 'int', 'CloseHandle', 'int', $hRemoteThread[0])
	
	;Free the previously allocated memory
	DllCall($KERNEL32, 'ptr', 'VirtualFreeEx', 'hwnd', $processHandle, 'int', $functionAddress[0], 'int', 0, 'int', 0x8000)
	DllCall($KERNEL32, 'ptr', 'VirtualFreeEx', 'hwnd', $processHandle, 'int', $packetAddress[0], 'int', 0, 'int', 0x8000)
	
	;Close the Process
	;memclose($processHandle)
	
	Return True
EndFunc		;==>
 
Верх