Yoko wrote:
обзор интересный но конечно нужны подробности.
по вышеперечисленному сходу замечания такие: что такое "КР" понятия не имею, "перейти к стандартной схеме ввода сообщений" - это жалоба не ко мне а в Origin, ходилка как раз и ставит всё на контроль в результате глючит ходьба на многих шардах.
всё остальное, если можно подробнее, потому что по намёкам мне абсолютно непонятно например какое отношение имеет хеширование к фришардам.
начиная с 6.0.5 версии клиента
Первичное подключение к ЛогинСерверу:
буфер = 0xEF
send(sock, буфер, ...)
Буфер = ИП (4 байта)
send(sock, буфер, ...)
Буфер = Версия (16 байт)
send(sock, буфер, ...)
Теперь подробней о "Версия"
теперь версия клиента строится так: А.Б.В.Г (как правило Г в обписании опускается, но возможно в будущем будет играть роль)
Формат BigEndian
Пример: 6.0.5.0
00 00 00 06 | 00 00 00 00 | 00 00 00 05 | 00 00 00 00
A Б В Г
Общий вид первой посылки до ответа сервера:
EF || 00 00 00 00 || 00 00 00 06 | 00 00 00 00 | 00 00 00 05 | 00 00 00 00
IP Версия
Правило формирования ИП не изменилось.
Следующие соединение с Логин сервером проходит по старым правилам. Версия нужна серверу для выробатки ЛогинКлючей (почти на всех РанУО шардах реализовано).
Проблема с инжектом была втом что инжект вешает хук на send. Тогда приходилось мудрить с SocketHook::send.
Так как первый раз он должен пропустить мимо 3 вызова, но приэтом скопировать ключ (IP). Хотя при повторном соединении (С игровым сервером) отсылается только IP и соответствено хук срабатывает тоько 1 раз (то есть надо уже разделять стадии подключения)
Это что касается подключения к 6.0.5 и тд.
Есть еще функция выроботки ключей (как минимум в 6.0.5, уже используется 2 ключа, второй просто продублирован)
Code:
-----
v0 = ((v0<<9|v1)<<10|v2)^((v2*v2)<<5);
Key_1 = (v0<<4)^(v1*v1)^(v1*0x0B000000)^(v2*0x380000)^0x2C13A5FD;
-----
v0 = (((v0<<9|v2)<<10|v1)*8)^(v2*v2*0x0c00);
Key_2 = v0^(v1*v1)^(v1*0x6800000)^(v2*0x1c0000)^0x0A31D527F;
Пример:
06 . 00 . 07
v0 | v1 | v2
v0 = 6
v1 = 0
v2 = 7
Key_1 = 2e9bc78d
Key_2 = a25bfe7f
Далее... MD5...а ну жен он для формирования в
Code:
void NewGameCrypt::decrypt(unsigned char * in, unsigned char * out, int len)
{
// NOTE: It seems this needs to change based on the m_seed (m_IP).
// Only used in Ver 2.0.4 and above.
// This table generated basec on DWORD id passed at start. 127.0.0.1
static const BYTE sm_bData[] = { 0x05, 0x92, 0x66, 0x23, 0x67, 0x14, 0xE3,
0x62, 0xDC, 0x60, 0x8C, 0xD6, 0xFE, 0x7C, 0x25, 0x69 };
// @ 04264A5 in 2.0.4
DWORD dwTmpIndex = dwIndex;
for ( int i=0; i<len; i++ )
{
out [i] = in[i] ^ sm_bData[dwTmpIndex%16];
dwTmpIndex++;
}
dwIndex = dwTmpIndex;
}
sm_bData:) у нас он от рождения константный:) а на ОСИ высчитывается через MD5 (что фришарды и использовали не долгое время:))
Code:
Packet: 0x8C
Sent By: Server
Size: 11 Bytes
Packet Build
BYTE[1] cmd
BYTE[4] gameServer IP
BYTE[2] gameServer port
BYTE[4] new key
тут нас интересует BYTE[4] new key (обозавем его
m_key). Он пригодится при вторичном логине. Пакет обрабатывается в handle_relay_server, ключик надо схранить...
Так вот
Code:
void NewGameCrypt::init()
{
uint8 tmpBuff[0x100];
memset(&ki,0,sizeof(ki));
memset(&ci,0,sizeof(ci));
int i;
makeKey(&ki,DIR_DECRYPT,0x80,NULL);
cipherInit(&ci,MODE_ECB,NULL);
ki.key32[0]=ki.key32[1]=ki.key32[2]=ki.key32[3]=m_IP;
//0x0100007f or 0x8edb49ad or may be client_ip xor 0x8fdb49d2
reKey(&ki);
for(i=0; i<256; i++)
m_subData3[i]=i;
blockEncrypt(&ci,&ki,m_subData3,256*8,tmpBuff);
memcpy(m_subData3,tmpBuff,256);
m_pos = 0;
dwIndex=0;
}
ki.key32[0]=ki.key32[1]=ki.key32[2]=ki.key32[3]=m_IP;
вот тут m_IP =
m_key
дальше инициализировали ШифрБлок для РЫБЫ:)
Дальше от этого блока (m_subData3) берем MD5 хэш и будет sm_bData в NewGameCrypt::decrypt
На этом вроде все с шифрованиями и подключениями.