avatar_SmallHabit

Гайд: Хукаем протокол DataServer'a, Я твой гайд, труба, шаталъ!

Автор SmallHabit, 2013 Янв. 21, 13:20

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

Ключевые слова [SEO] mu onlinemu разработкипротоколхукdataserver

SmallHabit

И так, совсем недавно понадобилось мне хукнуть протокол датасервера, по причине того что нужно было осуществить подгрузку доп. данных на сервер, всякие SQL решения в самом ГСе - не подходили, либо из-за своей глючности, либо по причине простого сжирания ресурсов. Мой взгляд пал на DataServer от вебзен, благо и сурсы сего чуда у меня имелись. Что уж говорить, вебзеновские датасервера - хороши, проверены временем и безотказны. Ещё давно меня посещали такие мысли, но ввиду того что раньше, толи не хватало знаний, толи просто из-за лени, осуществить отправку пакетов к ДатаСерверу посредством обычного хука не получалось, ГС крашил и отказывался нормально воспринимать все виды хуков, естественно я не опробовал только один вариант - _asm вызов функции на прямую. Как раз таки это был единственный вариант который мог заработать, и в итоге заработал. И речь как раз пойдёт про него =)

И так, приступим. У меня уже готов класс CDSProto, в нём обьявлены функции для принятия/отправки пакетов. Собственно нам теперь нужно хукнуть функцию принятия пакетов, а именно функцию DSProtocolCore, опустим момент поиска оффсетов, я уже знаю что для 1.00.18 ГСа это - 0x004057BD и 0x00424550.

Хукать мы будем на первый адрес, потому как любой вызов функции DSProtocolCore приведёт нас на первый адрес. И так, хукаем :
HookFunction((DWORD)&DSProtocolCoreEx, 0x004057BD);
Далее, нам нужно определить саму функцию DSProtocolCoreEx которая будет обрабатывать наши условия.
void DSProtocolCoreEx(BYTE protoNum, BYTE *aRecv, int aLen)
{
switch(protoNum)
{
case 0xF8:
DSProto.SetResetInfo((PMSG_ANS_RESET_INFO *)aRecv);
break;
}

DSProtocolCore(protoNum,aRecv,aLen);
}

А так-же определить вызов оригинальной функции, чтобы в итоге после обработки наших условий, функция возвращалась к её обычному режиму работы.
#define DSProtocolCore ((void(*) (BYTE,BYTE*,int)) 0x00424550 )
Вот и всё, в принципе, у нас уже готова половина, мы можем принимать данные с Датасевера. Но как датасервер узнает что нам нужно прислать? Правильно. Нужно научить наш ГС отправлять запросы и самому датасерверу.

Вся проблема заключается в том, что нельзя просто так взять и определить вызов оригинальной функции как это было с DSProtocolCore.
Спойлер
[свернуть]
Нагружать обьяснениями думаю не стоит, поэтому я выложу сам код, и пройдусь по строчкам отдельно. =)
void cDSProto::Send(char *buf,int len)
{
//---
SENDLEN = len; //Это ассемблер, тут свои тёрки!
memset(SENDBUFF,0,len); //Это ассемблер, тут свои тёрки!
memcpy(SENDBUFF,buf,len); //Это ассемблер, тут свои тёрки!
//---

_asm
{
MOV ECX, SENDLEN
PUSH ECX

LEA EDX, SENDBUFF
PUSH EDX

MOV ECX,0x006FCB78

mov dwTmpCall, 0x00401870
call dwTmpCall
}
}

И так, что мы имеем, функция Send принимающая параметры buf и len. Всё понятно, это пакет и его длина. Но что-же мы видим дальше! :O Почему мы переносим значения из параметров в заранее задекларированые переменные? Потому что _asm не воспринимает параметры на прямую, хотя по сути параметр len он принимает и проглатывает, но вот с buf уже проблемы, потому что он обьявлен как указатель на область памяти. Так-же помним про правило, что не обьявляются переменные в функциях где есть вставка _asm кода. Поэтому я заблаговременно определил их перед самой функцией, вот так
BYTE SENDBUFF[8192];
int SENDLEN;

Ну а насчёт, самой вставки, так это просто выдраный кусок кода из ГСа, который вызывает функцию отправки. По сути, если вам в этом коде ничего не понятно, можете смело его копировать и юзать.(Он рабочий, правда рабочий, проверенно на 500+ онлайне, при активном использовании).

Вот в принципе и всё. Наш ГС теперь умеет, принимать и отсылать пакеты на Датасервер. Что же нам ещё нужно для счастья? Правильно, картошка!
Спойлер
[свернуть]
А вот ссылка на исходники WZDataserver Source 4.5Season - DataServer - GameFront

SmallHabit


Похожие темы (5)