Хук функций winsock
recv
recvfrom
send
sendto
дублировать дескрипторы сокетов? Если да, то как это сделать???
Пробовал захукать connect без изменения запроса (т.е. в хуке вызывается родной коннект с теми же параметрами), а он обламывается...
Я еще веду перехват GetProcAddress и если ВоВ запрашивает одну из функций, которую перехватывает моя прога, то функция возвращает адрес моей функции - хука.
Помогите! Пишу прогу, которая имеет WoW.exe по нужнам API функциям. Нужно ли мне при перехвате функций
recv
recvfrom
send
sendto
дублировать дескрипторы сокетов? Если да, то как это сделать???
Пробовал захукать connect без изменения запроса (т.е. в хуке вызывается родной коннект с теми же параметрами), а он обламывается...
Я еще веду перехват GetProcAddress и если ВоВ запрашивает одну из функций, которую перехватывает моя прога, то функция возвращает адрес моей функции - хука.
Зачем те перехватывать пакеты? Ты знаеш заголовки и формат передаваемых данных и их содержимое? Есть спецификация или еще что?
Зачем те перехватывать пакеты? Ты знаеш заголовки и формат передаваемых данных и их содержимое? Есть спецификация или еще что?
Формат содержимого не нужен вообще.
Мне надо только лишь защитить пакеты от изменения
(WPE PRO, ...).
Для этого я перехватываю исходные данные, а отправляю закодированные.
Изначально данные не шифруються и в то же время во время передачи возникают ошибки. Не может ли это быть связано с тем, что хук, в отличие от главного модуля, может "не знать" каких-либо дескрипторов сокетов? Т.е. если бы отправлял главный модуль, то все ОК, а если отправляет мой хук то отправка идет в "неизвестный сокет".
Формат содержимого не нужен вообще.
Мне надо только лишь защитить пакеты от изменения
(WPE PRO, ...).
Для этого я перехватываю исходные данные, а отправляю закодированные.
Изначально данные не шифруються и в то же время во время передачи возникают ошибки. Не может ли это быть связано с тем, что хук, в отличие от главного модуля, может "не знать" каких-либо дескрипторов сокетов? Т.е. если бы отправлял главный модуль, то все ОК, а если отправляет мой хук то отправка идет в "неизвестный сокет".
Интересно ты знаеш как пользоваться WPE PRO,perm_edit,bwh поведуй или скинь мне на ящик инфу. А насчет сокетов,это надо смотреть каким образом перехватываемая функция отправляет данные. приведи участок кода ответсвенный за данное действие.
Интересно ты знаеш как пользоваться WPE PRO,perm_edit,bwh поведуй или скинь мне на ящик инфу. А насчет сокетов,это надо смотреть каким образом перехватываемая функция отправляет данные. приведи участок кода ответсвенный за данное действие.
Конкретного руководства по читам нет, толком я не разобрался сам.
А вот функция перехвата
int WINAPI I_recv(SOCKET s, char FAR* buf, int len, int flags)
{
int f_res;
BYTE* buff;
HGLOBAL mem;
DWORD crc;
mem=GlobalAlloc(GMEM_FIXED+GMEM_ZEROINIT,len);
if(!mem) return SOCKET_ERROR;
//
f_res=precv(s,(char FAR*)mem,len,flags);
if(f_res==SOCKET_ERROR)
{
GlobalFree(mem);
if(f_res==SOCKET_ERROR) send_log_message(s,"recv ERROR 2 ");
else send_log_message(s,"recv ERROR 3 ");
return SOCKET_ERROR;
}
/*crc=crc_data((PVOID)mem,f_res-4);
if(crc != *(DWORD*)((DWORD)mem+f_res-4))
{
GlobalFree(mem);
return SOCKET_ERROR;
}*/ // это проверка CRC32 на совпадение
//CopyMemory((PVOID)buf,(PVOID)mem,f_res-4);
CopyMemory((PVOID)buf,(PVOID)mem,f_res);
GlobalFree(mem);
return f_res;
}
int WINAPI I_send(SOCKET s, const char FAR* buf, int len, int flags)
{
int f_res;
DWORD crc;
HGLOBAL mem;
//mem=GlobalAlloc(GMEM_FIXED+GMEM_ZEROINIT,len+4);
//if(!mem) return SOCKET_ERROR;
//CopyMemory((PVOID)mem,(PVOID)buf,len);
//crc=crc_data((PVOID)buf,len);
//*(DWORD*)((DWORD)mem+len)=crc;
//f_res=psend(s,(const char FAR*)mem,len+4,flags);
f_res=psend(s,(const char FAR*)buf,len,flags);
//GlobalFree(mem);
if(f_res==SOCKET_ERROR) return SOCKET_ERROR;
//
send_log_message(s,"send ok");
return f_res;
}
В функции I_send так вообще преобразований не стоит...
psend,precv - указатели на функции, выдранные еще
при запуске проги из wsock32.dll
Насчет psend и precv я что то сомневаюсь покажи их объявление,но это потом. Каким образом у тебя происходит подмена оригинальных функций(send,recv) на свои(I_send,I_recv)? В чем проблема в каких именно строчках,в каких функциях,какой возвращяемый код ошибки. По твоему в каком контексте происходит вызов твоих функций(I_send,I_recv) - в твоем или в перехватываемом. Где расположены данные функции((I_send,I_recv,psend,precv)- exe или dll?
1.
pLoadLibrary=LoadLibrary;
pGetProcAddress=GetProcAddress;
...
ws32=pLoadLibrary("wsock32.dll");
precv=(PRECV)pGetProcAddress(ws32,"recv");
precvfrom=(PRECVFROM)pGetProcAddress(ws32,"recvfrom");
psend=(PSEND)pGetProcAddress(ws32,"send");
psendto=(PSENDTO)pGetProcAddress(ws32,"sendto");
2.
Метод внедрения - подмена адресов в таблицах импорта. Работает на 100%. Хуки вызываются на 100%.
3.
Мои хуки вызываются из главного процесса, а не из его библиотек, т.к. подмену адресов я делаю только в главном процессе WoW.
4.
Хуки расположены в DLL. эта DLL расположена в адресном пространстве процесса WoWа - я делал LoadLibrary из потока главного процесса.
5.
После инжекта исчезает загрузочный модуль, остается только WoW и моя библиотека.
6.
int WINAPI I_recv(SOCKET s, char FAR* buf, int len, int flags)
{
int f_res;
BYTE* buff;
HGLOBAL mem;
DWORD crc;
mem=GlobalAlloc(GMEM_FIXED+GMEM_ZEROINIT,len);
if(!mem) return SOCKET_ERROR;
//
f_res=precv(s,(char FAR*)mem,len,flags);
if(/*(f_res<=4) || */f_res==SOCKET_ERROR)
{
GlobalFree(mem);
if(f_res==SOCKET_ERROR) send_log_message(s,"recv ERROR 2 "); <<< Тут ошибка, в игре "disconnected from server"
else send_log_message(s,"recv ERROR 3 ");
return SOCKET_ERROR;
}
/*crc=crc_data((PVOID)mem,f_res-4);
if(crc != *(DWORD*)((DWORD)mem+f_res-4))
{
GlobalFree(mem);
return SOCKET_ERROR;
}*/ // это проверка CRC32 на совпадение
//CopyMemory((PVOID)buf,(PVOID)mem,f_res-4);
CopyMemory((PVOID)buf,(PVOID)mem,f_res);
GlobalFree(mem);
return f_res;
}
Перед этим 3 recv с этого же сокета проходят нормально...
Логи:
[31-5-2006 13:59:6] socket af=2, type=SOCK_STREAM, proto=0
[31-5-2006 13:59:6] socket result=0
[31-5-2006 13:59:6] socket af=2, type=SOCK_STREAM, proto=0
[31-5-2006 13:59:6] socket result=1
[31-5-2006 13:59:11] socket af=2, type=SOCK_STREAM, proto=0
[31-5-2006 13:59:11] socket result=3
[31-5-2006 13:59:11] send from 3
[31-5-2006 13:59:11] send ok from 3
[31-5-2006 13:59:12] recv from 3
[31-5-2006 13:59:12] send from 3
[31-5-2006 13:59:12] send ok from 3
[31-5-2006 13:59:12] recv from 3
[31-5-2006 13:59:12] send from 3
[31-5-2006 13:59:12] send ok from 3
[31-5-2006 13:59:12] recv from 3
[31-5-2006 13:59:12] socket af=2, type=SOCK_STREAM, proto=0
[31-5-2006 13:59:12] socket result=4
[31-5-2006 13:59:12] recv from 4
[31-5-2006 13:59:12] recv from 4
[31-5-2006 13:59:12] recv from 4
[31-5-2006 13:59:12] recv ERROR 2 from 4
Цифрами после from обозначены условные номера сокетов.
После socket result= - они же.
PS: После ошибки "recv ERROR 2" WSAGetLastError возвращает 0!!!???
Попробуй сделать так для начала:
int WINAPI I_recv(SOCKET s, char * buf, int len, int flags)
{
return precv(s,buf,len,flags);
}
и аналогично для I_send
терь инжекть такую длл и смотри не будет ли сбоев в вове. затем сообщиш результаты. Если будет такая же хрень то скорее всего это будет нестабильность данного подхода если же нет будем смотреть дальше.
if((f_res<=4) || (f_res==SOCKET_ERROR))
{
GlobalFree(mem);
if(f_res==SOCKET_ERROR) send_log_message(s,"recv ERROR 2 ");
else send_log_message(s,"recv ERROR 3 ");
//send_log_message_error(s,err);
return SOCKET_ERROR;
}
Надо
if((f_res<=4) || (f_res==SOCKET_ERROR))
{
err=WSAGetLastError();
GlobalFree(mem);
if(f_res==SOCKET_ERROR) send_log_message(s,"recv ERROR 2 ");
else send_log_message(s,"recv ERROR 3 ");
//send_log_message_error(s,err);
WSASetLastError(err);
return SOCKET_ERROR;
}
Проверил. Работает, правда в игре пинг под 3000.
Добавил подсчет CRC - стала игра вылетать.
Полная версия хуков во вложении.
Вообще я сделал подобное только для DarkSwords. Но можно сделать проще: создать свою библиотеку WSOCK32 и положить её рядом с исполнимым файлом.
Можно конечно. Но приложение может воспользоваться методом LoadLibrary/GetProcAddress, и тогда все рухнет.
Зачем те нужен подсчет crc не пойму? Если нужен то его суть и алгоритм.
Я пишу античит. Я должен защитить данные от изменения читами или хотя бы обнаружить это изменение. Для этого после каждого пакета я отправляю контрольную сумму этого пакета. Если произойдет изменение то изменится содержимое пакета и/или контрольная сумма. При получении пакета сервером хук на сервере сверяет контрольную сумму с реальной и если они не равны, то делает вид, что произошла ошибка сокета.
Контрольная сумма считается на сервере и на клиенте одним и тем же алгоритмом и одним и тем же полиномом (я бы даже сказал одним и тем же кодом).
--- Код, реализующий подсчет CRC32 ---
#include <windows.h>
// standart polynom
#define CRC_POLYNOM 0xedb88320
// non-standart polynom
//#define CRC_POLYNOM 0xde8b3802
DWORD crc_table[256];
DWORD crc_poly=0;
void crc_calc_table(DWORD poly)
{
int i,j;
DWORD z;
for(i=255;i>=0;i--)
{
z=i;
for(j=0;j<8;j++)
{
if(z & 1)
z = (z >> 1) ^ poly;
else
z >>= 1;
}
crc_table=z;
}
}
DWORD crc_data_polynom(DWORD poly,PVOID data,DWORD size)
{
DWORD i,crc;
BYTE b;
if(crc_poly!=poly) crc_calc_table(poly);
crc=(DWORD)(-1);
for(i=0;i<size;i++)
{
b=(BYTE)(crc & 0xff);
crc=crc >> 8;
b=b ^ (*(BYTE *)((DWORD)data+i));
crc=crc ^ crc_table;
}
return crc ^ ((DWORD)(-1));
}
DWORD crc_data(PVOID data,DWORD size)
{
return crc_data_polynom(CRC_POLYNOM,data,size);
}
DWORD crc_file(LPCSTR fname)
{
HFILE f;
DWORD crc;
int res;
BYTE c,b;
f=_lopen(fname,OF_READ);
if(f==HFILE_ERROR) return 0;
if(crc_poly!=CRC_POLYNOM) crc_calc_table(CRC_POLYNOM);
crc=(DWORD)(-1);
while(1)
{
res=_lread(f,&c,1);
if(res!=1) break;
b=(BYTE)(crc & 0xff);
crc=crc >> 8;
b=b ^ c;
crc=crc ^ crc_table;
}
_lclose(f);
return crc ^ ((DWORD)(-1));
}
#define ENABLE_LOGGING
...
В коде хуков
#ifdef ENABLE_LOGGING
log_data(1,(PVOID)mem,f_res);
#endif
Из-за этого пинг у меня поднимался аж до 17000.
Когда убрал "#define ENABLE_LOGGING" - 2ms
Еще одна проблема (и самая главная):
Мой хук не перехватывает ни одной функции сети WowEmu. Надо искать другие методы. Вы можете мне что-нибудь предложить? Есть какие-нибудь другие подходы?
Есть ли какой-нибудь метод, который подходит и для WoWWoW (он на C#.NET написан)?