PDA

Просмотр полной версии : Проблема с L2 Init Blowfish


i_am_kisly
13.11.2014, 11:44
День добрый, начал писать свой чат-клиент под android на Csharp/xamarin.
Столкнулся с проблемой дешифрования блоуфишем.

Набросал самый простой минимальный код без излишеств, скриншот output'а прилагаю.



using System;
using System.Text;

namespace l2packet
{
unsafe class MainClass
{
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;

byte[] bytes = new byte[NumberChars / 2];

for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);

return bytes;
}

public static void Main (string[] args)
{
byte[] STATIC_BLOWFISH_KEY = new byte[32];
string key = "6B60CB5B82CE90B1CC2B6C556C6C6C6C";
//or
STATIC_BLOWFISH_KEY[0] = 0x6B;
STATIC_BLOWFISH_KEY[1] = 0x60;
STATIC_BLOWFISH_KEY[2] = 0xCB;
STATIC_BLOWFISH_KEY[3] = 0x5B;
STATIC_BLOWFISH_KEY[4] = 0x82;
STATIC_BLOWFISH_KEY[5] = 0xCE;
STATIC_BLOWFISH_KEY[6] = 0x90;
STATIC_BLOWFISH_KEY[7] = 0xB1;
STATIC_BLOWFISH_KEY[8] = 0xCC;
STATIC_BLOWFISH_KEY[9] = 0x2B;
STATIC_BLOWFISH_KEY[10] = 0x6C;
STATIC_BLOWFISH_KEY[11] = 0x55;
STATIC_BLOWFISH_KEY[12] = 0x6C;
STATIC_BLOWFISH_KEY[13] = 0x6C;
STATIC_BLOWFISH_KEY[14] = 0x6C;
STATIC_BLOWFISH_KEY[15] = 0x6C;

//C200 вырезал заголовок с размером из пакета
string str = "9B09F43C6A02BE5DD3D485782B8F54B46F15D32B602D6D9330 A3A40519291A8C193BC97F0F05CD004DADD2B01C3B494195DF AE760E00C576690E141826583405CF573B374E2ED2DC0270D8 DADB7294F03CDF5757E4CC7D4BD45F73CDABA5C3D53D3A46B8 E4E1A5FCB5E1695E05EBD8FF2702FFE6E5FF5B5367FB926F5D FED57A84E5BAD3901EB97E788804F6F03625B82637C2C5E017 0FDFECA65FEDA0D5177899AB73432E83182547B870D923554C 03A0AB2F50375D0631A27D68707A147A37";
byte[] bytes_ = StringToByteArray (str);

additionals ad = new additionals();

fixed (byte *pbuf = &bytes_[0]){ //TODO: add overload view_raw_data( <- byte of array) later
ad.view_raw_data(pbuf,true,192);
}

L2_login.NewCrypt newc = new L2_login.NewCrypt (STATIC_BLOWFISH_KEY);
byte[] res = newc.decrypt (bytes_);

fixed (byte *ppbuf = &res[0]){
ad.view_raw_data(ppbuf,true,192);

}

}
}
}



На выводе получаю явно что-то не то (
http://coderx.ru/attachment.php?attachmentid=2920&stc=1&d=1415864210
Использовал исходники L2.net (он же L2_Login) (http://coderx.ru/attachment.php?attachmentid=2921&stc=1&d=1415864409)
Что я делаю не так ?

wimax
13.11.2014, 23:57
Бля ну и задроты пошли)))))))

i_am_kisly
14.11.2014, 09:53
задротство тут не при чем, академический интерес.

Antharas
14.11.2014, 19:30
А че только на чате останавливаться?) может ООГ клиент для мобилы напишешь?)

wimax
16.11.2014, 03:32
http://fursoffers.narod.ru/Packets.htm

i_am_kisly
16.11.2014, 19:03
А че только на чате останавливаться?) может ООГ клиент для мобилы напишешь?)

я вижу в твоем сообщении иронию.. а зря!

Добавлено через 51 секунду
http://fursoffers.narod.ru/Packets.htm

т.е .в начале надо проделать расшифровать xor ?

wimax
17.11.2014, 04:57
Пакеты сервера авторизации шифруются по алгоритму Blowfish. Стандартный ключ по умолчанию в 4-х хрониках:
5F 3B 35 2E 5D 39 34 2D 33 31 3D 3D 2D 25 78 54 21 5E 5B 24. К концу ключа прибавляется символ с кодом 0. В Interlude тип шифрования был изменен - пакет
Init содержит динамический Blowfish ключ случайно генерируемый для каждого клиента. Этот пакет сначала шифруется по алгоритму XOR(ключ генерируется
случайным образом и помещается в конце пакета), а потом шифруется по алгоритму Blowfish, статическим ключом. По умолчанию статический ключ -
6B 60 CB 5B 82 CE 90 B1 CC 2B 6C 55 6C 6C 6C 6C. Все последующие пакеты будут шифроваться динамическим Blowfish ключом. Пакет LoginRequest дополнительно
шифруется по алгоритму RSA. Ключ состоит из следующих частей: B = 1024, E = 65537, N = передается в пакете Init. Вместе эти 3 части составляют целый RSA
ключ. Байты N в пакете зашифрованы функцией:

r00tk1d
18.11.2014, 14:02
Есть у кого-то пример на C/C++ как именно ксорить пакет Init?

supernewbie
18.11.2014, 23:57
реализация логина на Delphi 7

Antharas
19.11.2014, 15:14
я вижу в твоем сообщении иронию.. а зря!

Да я вобще с радостью по разбирался бы в этом деле вместе.

r00tk1d
19.11.2014, 17:09
Люди помогите!!! :((( никак не получается с этим пакетом Init... Вроде бы всё верно делаю, но клиент Interlude никак не реагирует на такой пакет... А Ertheia вообще критует..

static void XorInitPacket(unsigned char* raw, int size, int key)
{
int i = 0;
int key2 = key;
for(i = 6; i < size - 4; i+=4)
{
int temp = (*(raw + i + 3) << 24) & 0xFF000000 | (*(raw + i + 2) << 16) & 0xFF0000 | (*(raw + i + 1) << 8) & 0xFF00 | *(raw + i) & 0xFF;
key2 += temp;
int temp2 = key2 ^ temp;
raw[i] = temp2 & 0xFF;
raw[i + 1] = temp2 >> 8 & 0xFF;
raw[i + 2] = temp2 >> 16 & 0xFF;
raw[i + 3] = temp2 >> 24 & 0xFF;
}
raw[i] = key2 & 0xFF;
raw[i + 1] = key2 >> 8 & 0xFF;
raw[i + 2] = key2 >> 16 & 0xFF;
raw[i + 3] = key2 >> 24 & 0xFF;
};

void CUserSocket::OnCreate()
{
m_pAuthUser = new CAuthUser;
m_pAuthUser->Init();

srand(time(NULL));

*(int*)(m_bwKey) = rand();
*(int*)(m_bwKey + 4) = rand();
*(int*)(m_bwKey + 8) = rand();
*(int*)(m_bwKey + 0xc) = rand();

m_pCrypt = new CBlowFish(g_bfStaticKey, sizeof(g_bfStaticKey));

CIOBuffer* pBuffer = CIOBuffer::Alloc();

int nLen = Assemble(pBuffer->m_Buffer + 2, IOBUFFER_SIZE, "cddbddddbc",
0,
1234567, // Session ID
0x0000c621, // protocol version
sizeof(m_pAuthUser->m_RSA),
&m_pAuthUser->m_RSA, // public key
0x29DD954E,
0x77C39CFC,
0x97ADB620,
0x07BDE0F7,
sizeof(m_bwKey),
m_bwKey, // new BlowFish Key
0
);

nLen += 8; // xor key
nLen = (nLen + 7) & 0xfffffff8; // aligment for blowfish

XorInitPacket(pBuffer->m_Buffer, nLen, rand());

m_pCrypt->Encrypt(pBuffer->m_Buffer + 2, nLen); // blowfish encrypt
nLen+=2; // packet total size

Read(0); // WSARead() IOCP early call

*(short*)(pBuffer->m_Buffer) = nLen; // set first bytes to length of packet
pBuffer->m_dwSize = nLen // for WSASend
Write(pBuffer); // Write!

delete m_pCrypt; // change blowfish key
m_pCrypt = new CBlowFish(m_bwKey, sizeof(m_bwKey));
}


Улетает клиенту вот такое
00000000: ba 00 e7 22 01 4f 2b 42 68 b1 b9 06 e8 a2 ac a4
00000010: 17 97 94 2f 4b da 02 02 36 bb 65 02 33 77 fb b4
00000020: c7 64 23 cf eb b1 c2 fb 97 11 d3 85 19 1e 42 5e
00000030: 46 f8 fc aa 4f 34 eb cc 39 b0 02 98 fd e0 21 9d
00000040: dc 5c d3 dd e3 b5 4d fa 38 46 6f 02 d4 4c 9d ce
00000050: e8 46 9b 88 1b 01 4f cc 69 52 7d ae b5 5e e1 92
00000060: 3a 6e 92 43 7a c3 82 17 06 2e d2 27 53 1c 25 98
00000070: 53 ca 27 56 60 e3 9f 14 f6 54 9f bf 9f 48 c8 ed
00000080: d8 28 e9 93 96 d3 16 7a c9 81 b4 52 c2 d9 8b dd
00000090: 42 3f 59 cf 1a 11 a3 fa 0c 9b 46 94 e3 0f 91 fb
000000a0: a7 9f 0a f0 42 ec f2 07 66 ae 86 10 6d 62 cf 12
000000b0: 01 3b e2 0b ec 99 3d 8b 23 b0

оно же до ксора и шифрования (но с ксор ключом в конце пакета)

00000000: ba 00 00 87 d6 12 00 21 c6 00 00 6e 12 32 ab a3
00000010: 1a ee 4c eb 97 09 25 f8 e5 25 ad db d7 80 e1 20
00000020: 4c 72 d7 1d b4 fb fb c0 7e e9 3d d0 b8 87 3f b1
00000030: 1c fe ad 5d 17 08 2c 18 9b 26 ec 61 6e 32 95 73
00000040: 95 7e 37 3d 03 d4 14 be 43 b8 92 3b b2 d1 76 e3
00000050: a3 0e 87 7d a5 ee ed 69 56 59 57 5f ee c6 17 35
00000060: 81 10 f7 43 74 32 03 c4 46 c9 e3 a5 d6 29 a6 a6
00000070: a5 3d c8 e6 af dc 35 19 43 21 0a 2e d8 12 a7 6c
00000080: 11 d1 a5 ab b1 d6 85 44 72 fb 93 4e 95 dd 29 fc
00000090: 9c c3 77 20 b6 ad 97 f7 e0 bd 07 27 1d 6e 6e e0
000000a0: 09 a9 14 24 7c a1 10 0f 0b 06 6a 00 cc cc cc cc
000000b0: cc cc cc cc cc cc d2 ab 71 63

что у меня может быть не так? Нигде не могу найти точного примера ксора инит пакета :confused:

wimax
23.11.2014, 04:51
void scrambleMod( char *n )
{
typedef unsigned char byte;
int i;

for( i=0; i<4; i++ ) {
byte temp = n[0x00 + i];
n[0x00 + i] = n[0x4d + i];
n[0x4d + i] = temp;
};

// step 2 xor first 0x40 bytes with last 0x40 bytes
for( i=0; i<0x40; i++ ) {
n[i] = (byte)(n[i] ^ n[0x40 + i]);
};

// step 3 xor bytes 0x0d-0x10 with bytes 0x34-0x38
for( i=0; i<4; i++ ) {
n[0x0d + i] = (byte)(n[0x0d + i] ^ n[0x34 + i]);
};

// step 4 xor last 0x40 bytes with first 0x40 bytes
for( i=0; i<0x40; i++ ) {
n[0x40 + i] = (byte)(n[0x40 + i] ^ n[i]);
};
};


Не ужели так трудно?

r00tk1d
24.11.2014, 15:52
Шутка в том, что не трудно. в начале функци CUserSocket::OnCreate
m_pAuthUser = new CAuthUser;
m_pAuthUser->Init();
где

R_RANDOM_STRUCT *CAuthUser::InitRandomStruct(void)
{
static unsigned char seedByte = 0;
unsigned int bytesNeeded;
static R_RANDOM_STRUCT randomStruct;

R_RandomInit(&randomStruct);
srand((unsigned)time(NULL));

while (1) {
seedByte = rand();
R_GetRandomBytesNeeded(&bytesNeeded, &randomStruct);
if(bytesNeeded == 0)
break;

R_RandomUpdate(&randomStruct, &seedByte, 1);
}

return(&randomStruct);
}

void CAuthUser::scrambleModulus()
{
unsigned char *scrambledMod = m_RSA, temp;

memcpy(m_RSA, m_rsaPubKey.modulus, 0x80);

// step 1 : 0x4d-0x50 <-> 0x00-0x04
for (int i = 0; i < 4; i++)
{
temp = scrambledMod[0x00 + i];
scrambledMod[0x00 + i] = scrambledMod[0x4d + i];
scrambledMod[0x4d + i] = temp;
}
// step 2 : xor first 0x40 bytes with last 0x40 bytes
for (int i = 0; i < 0x40; i++)
{
scrambledMod[i] = (scrambledMod[i] ^ scrambledMod[0x40 + i]);
}
// step 3 : xor bytes 0x0d-0x10 with bytes 0x34-0x38
for (int i = 0; i < 4; i++)
{
scrambledMod[0x0d + i] = (scrambledMod[0x0d + i] ^ scrambledMod[0x34 + i]);
}
// step 4 : xor last 0x40 bytes with first 0x40 bytes
for (int i = 0; i < 0x40; i++)
{
scrambledMod[0x40 + i] = (scrambledMod[0x40 + i] ^ scrambledMod[i]);
}
}

void CAuthUser::Init()
{
R_RANDOM_STRUCT *randomStruct;
R_RSA_PROTO_KEY protoKey;

randomStruct = InitRandomStruct();
protoKey.bits = 1024;
protoKey.useFermat4 = 1;
if(R_GeneratePEMKeys(&m_rsaPubKey, &m_rsaPrivKey, &protoKey, randomStruct)) {
MessageBox(NULL, L"ERROR", L"Error", MB_OK || MB_ICONSTOP);
return;
}
scrambleModulus();
}

i_am_kisly
24.11.2014, 17:48
Если кто-нибудь "из старших товарищей" заглядывает сюда, то может поделится чейндж-логом, как меняется протокол от хроник к хроникам ? Я хочу сделать мульти хронико-троно-протокольный Android L2Chat ) и данная информация была бы очень полезна.

i_am_kisly
31.12.2014, 11:47
Я не могу разобраться с асинхронными сокетами, прошу посильной помощи от вас.
Задача следующая :
1. Есть некий сервер (но мы то знаем.. что это L2), который после подключения клиента может в любой момент прислать данные, и клииент должен успеть их принять.
2. Если пришедший пакет требует ответа, то ответить не медля.
3. В случае некоторого евента ( например нажатия кнопки ) отправляем пакет.

Я позолил себе набросать небольшую схему, как я это вижу.

http://img.radiokot.ru/files/21274/thumbnail/jcilnr8tu.png (http://img.radiokot.ru/files/21274/medium/jcilnr8tu.png)

Архитектура приложения с асинхронными сокетами
Receive - в цикле, Send - c кнопки и\или ответом. Чего не хватает ?

Чего я не понимаю:
1) как определить что в сокет пришли данные ?
2) можно ли не гонять цикл, а ждать некоторого interrupt , который оповестит о готовности некоторого обьема данных ?
3) ???

Очень надеюсь на вашу помощь. С наступающим новым годом и рождеством !!

http://www.cyberforum.ru/attachments/473227d1419887718

xixi
01.01.2015, 05:37
Если кто-нибудь "из старших товарищей" заглядывает сюда, то может поделится чейндж-логом, как меняется протокол от хроник к хроникам ? Я хочу сделать мульти хронико-троно-протокольный Android L2Chat ) и данная информация была бы очень полезна.
Большинство пакетов одинаковые. В частности логин сервер и say2.

i_am_kisly
01.01.2015, 22:09
написал тут :
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace l2packet
{
class SocketAsyncClient
{
public Socket client;

public byte[] in_data = new byte[0xFFFF];
public byte[] out_data = new byte[0xFFFF];


public SocketAsyncClient()
{
this.connect (ref client);
while (true) {
this.s_read ();

}
client.Shutdown (SocketShutdown.Both);
client.Close ();
}


public void connect(ref Socket sock)
{
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
Console.WriteLine("Сокет успешно создан");
client.Connect("127.0.0.1", 2106);
Console.WriteLine("Соединение успешно установлено");
}
catch (SocketException ex)
{
Console.WriteLine("Ошибка при работе с сокетами: " + ex.Message);
}
}


public int s_read()
{
byte[] data = new byte[1024];
// … заполнение массива data опущено
SocketAsyncEventArgs async_e = new SocketAsyncEventArgs();
async_e.SetBuffer(data, 0, 1024);
async_e.Completed += SocketAsyncCompleted;
client.ReceiveAsync(async_e);
Console.WriteLine("Нажмите любую клавишу");
Console.ReadKey();
Console.WriteLine ("Приняты байты : {0} {1}", data [0], data [1]);
return 0;
}

public int s_send()
{
byte[] data = new byte[1024];
// … заполнение массива data опущено
SocketAsyncEventArgs async_e = new SocketAsyncEventArgs();
async_e.SetBuffer(data, 0, 1024);
async_e.Completed += SocketAsyncCompleted;
client.SendAsync(async_e);
return 0;
}

void SocketAsyncCompleted(object o, SocketAsyncEventArgs e)
{
if(e.LastOperation == SocketAsyncOperation.Send)
{
if(e.SocketError == SocketError.Success)
Console.WriteLine("Передача выполнена успешна");
else
Console.WriteLine("При передаче произошла ошибка");
}
if(e.LastOperation == SocketAsyncOperation.Receive)
{
if(e.SocketError == SocketError.Success)
Console.WriteLine("Прием выполнен успешно");

else
Console.WriteLine("При приеме произошла ошибка");
}
}


}
}

обьясните, почему если нет задержки, обусловленной Console.ReadKey();, то код возвращает пустой массив. как этого избежать ?

Добавлено через 2 часа 46 минут
догнал до подправил до :
Код:
public int s_read()
{
byte[] data = new byte[1024];
// … заполнение массива data опущено
SocketAsyncEventArgs async_e = new SocketAsyncEventArgs();
async_e.SetBuffer(data, 0, 1024);
async_e.Completed += SocketAsyncCompleted;
while (true) {
if (client.Available > 0) {
client.ReceiveAsync (async_e);
Console.WriteLine ("Приняты байты : {0} {1}", data [0], data [1]);
break;
}
}
return 0;
}


не слишком убого ?

Yegor
02.01.2015, 12:47
Товарищи объясните, а зачем вы это делаете? Идея ООГ бота для мобильного устройства интересна и меня тоже посещала. Но где это будет работать? Сейчас 100% популярных L2 серверов имеют доп шифрацию и это все там работать не будет.

i_am_kisly
02.01.2015, 17:33
just for fun )))

может кто поможет и поделится сетевым модулем ?

Kolka
06.01.2015, 00:36
А по L2 Classic есть информация?

У меня от сервера пакет Init приходит размером 194 байта, что с ними делать?

cvillian
30.06.2015, 05:30
реализация логина на Delphi 7

На дельфи 7 всё работает.

Вот на ХЕ 7 не хочет, проэкт компилируется норм, без ошибок, но на втором пакете дисконект. Никак не найду проблемы.

Yegor
30.06.2015, 11:27
В делфи ХЕ тип String теперь двухбайтный, если он где то используется в алгоритме , то это нужно учитывать.
Например заменив на AnsiString;

cvillian
30.06.2015, 16:34
В делфи ХЕ тип String теперь двухбайтный, если он где то используется в алгоритме , то это нужно учитывать.
Например заменив на AnsiString;
спасибо, буду пробовать

ScythLab
30.06.2015, 17:56
И еще Char заменить на AnsiChar, а также Chr лучше заменить на AnsiChar

cvillian
01.07.2015, 10:01
Да спасибо, помогло :)

Добавлено через 3 часа 32 минуты
В первом пакете GS (Init) идёт постоянный массив, я его смотрю черз WP PPC, т.е. он у меня есть в виде хекса. Никак не пойму во что мне его переконвертировать чтобы вставить в пакет. пакет это array of byte

Добавлено через 8 часов 47 минут
с этим вроде разобрался - HexToStr
теперь надо с числами что-то придумать, в WPF есть функция IntToBin, вот нужно что-то подобное

Yegor
01.07.2015, 11:48
Просто копируете данные в нужное место, например у нас есть массив
pck: array[1024] of byte;

Чтобы в него в нужное место поместить 4 байтное Int значение делаете:

Move(откуда, куда, количество байт);

Move(intVal, pck[100], SizeOf(intVal));

Эта конструкция скопирует значение переменной intVal в массив начиная с 100 позиции. Для других типов данных кроме текста, аналогично.


Можете также воспользоваться готовыми функциями из исходников пакетхака:

function ReadC(const pck: string; var index:integer):byte; stdcall;
function ReadH(const pck: string; var index:integer):word; stdcall;
function ReadD(const pck: string; var index:integer):integer; stdcall;
function ReadQ(const pck: string; var index:integer):int64; stdcall;
function ReadF(const pck: string; var index:integer):double; stdcall;
function ReadS(const pck: string; var index:integer):string; stdcall;
procedure WriteC(var pck: string; const v:byte; ind:integer=-1); stdcall;
procedure WriteH(var pck: string; const v:word; ind:integer=-1); stdcall;
procedure WriteD(var pck: string; const v:integer; ind:integer=-1); stdcall;
procedure WriteQ(var pck: string; const v: Int64; ind:integer=-1); stdcall;
procedure WriteF(var pck: string; const v:double; ind:integer=-1); stdcall;
procedure WriteS(var pck: string; const v: WideString; ind:integer=-1); stdcall;

Но они заточены на то что пакет хранится в переменной типа String.

cvillian
01.07.2015, 20:01
Ну это когда нужно изменить пакет. Я говорю про то когда его нужно собрать. В WP PPC мого удобных функций для этого есть, надо видима придумывать что-то похожее. Я тоже думаю пакет в стринге держать.

Yegor
01.07.2015, 23:38
Ну это когда нужно изменить пакет. Я говорю про то когда его нужно собрать. В WP PPC мого удобных функций для этого есть, надо видима придумывать что-то похожее. Я тоже думаю пакет в стринге держать.

Эти функции именно и созданы чтобы его собрать.

procedure WriteC(var pck: string; const v:byte; ind:integer=-1); stdcall;
procedure WriteH(var pck: string; const v:word; ind:integer=-1); stdcall;
procedure WriteD(var pck: string; const v:integer; ind:integer=-1); stdcall;
procedure WriteQ(var pck: string; const v: Int64; ind:integer=-1); stdcall;
procedure WriteF(var pck: string; const v:double; ind:integer=-1); stdcall;
procedure WriteS(var pck: string; const v: WideString; ind:integer=-1); stdcall;

На самом деле очень удобно.

Берем пустую переменную типа String и последовательно пишем в нее ID, и прочие данные.

Например:


// Создаем пакет для посылки текста в чат
function Say2(text: WideString; textType:integer; targetChar: ShortString = ''): string;
begin
Result:= #$49;
WriteS(Result, text);
WriteD(Result, textType);
if(targetChar <> '')and(textType = 2) then WriteS(Result, targetChar);
SendPacket(result);
end;

cvillian
02.07.2015, 22:41
Вобщем вроде как законектился я к гейм серверу. Но после того как я отсылаю 4-й пакет - CharSelected, Рич эдит вдруг начинает заполнятся нулями и приложение виснет, хотя дальнейшие пакеты я не обрабатываю и не пишу в лог. Из за чего такое может быть? Может потому что сокет слушается через сообщения форме?

Добавлено через 1 час 19 минут
походу где-то ошибка просто, логер пытается показать пакет размером с несколько десятков или больше мб., непойму откуда он его взял :) поставил проверку в логере на размер и сразу залогинился :)

Добавлено через 11 часов 3 минуты
Может кто встречал исходники конекта к логин серверу на с++?

Добавлено через 4 часа 10 минут
Не совсем пойму такую вещь, пакеты могут приходить слепленными, их нужо сначала ралеплять и потом декодировать или декодировать всю пришедшую кучу, а потом разлеплять

Yegor
03.07.2015, 02:05
Не совсем пойму такую вещь, пакеты могут приходить слепленными, их нужо сначала ралеплять и потом декодировать или декодировать всю пришедшую кучу, а потом разлеплять

Пакеты могут приходить как попало. По 2, полтора, полпакета. Надо читать размер пакета (первые 2 байта) и затем ждать приема нужного количества байт из сокета.

SeregaZ
03.07.2015, 07:09
это дааа :) целая история с этими "слепленными" пакетами :)

cvillian
03.07.2015, 07:38
млин не простая штука получается) Если пришло пол пакета, это не значит что в следующий раз прийдёт вторая, может прийти половина предыдущего
и ещё кусок)

Yegor
03.07.2015, 10:47
Я когда то долго вылавливал периодические краши бота, оказалось иногда принимался только 1 байт размера пакета, поэтому это нужно тоже проверять и ждать следующего байта.

cvillian
03.07.2015, 12:05
а пакеты могу не по порядку идти? т.е. я жду половину одного пакета, а вместо этого приходить другой, и только после него нужная мне часть

Yegor
03.07.2015, 13:34
а пакеты могу не по порядку идти? т.е. я жду половину одного пакета, а вместо этого приходить другой, и только после него нужная мне часть

Все по порядку.

cvillian
03.07.2015, 13:37
Все по порядку.
Ну хоть это радует, а то я на allcheats начитался ужасов)

Yegor
03.07.2015, 14:37
Пакеты приходят кусками не потому что так их шлет сервер, а потому что так работает протокол TCP.

cvillian
20.07.2015, 15:07
У меня похоже не правильный алгоритм кодировки пакета. После того как пакет кодируется и отправляется, в WP PPC я вижу что каждый 16-й байт =
1А:

[106] C>s 0ms. 13:57:15 .481 20.07.15
-------------------------------------------------------------------------------
TType: LA2 Server: GS3 Parse: 2 (auto) EnCode: DT2 KT4 (auto)
------- 0 1 2 3 4 5 6 7 - 8 9 A B C D E F -------------------
000000 3F 00 49 70 00 72 00 69 | 00 76 1A 65 00 74 00 20 ?.Ip.r.i.v.e.t.
000010 00 70 00 72 00 69 00 76 | 00 65 1A 74 00 20 00 70 .p.r.i.v.e.t. .p
000020 00 72 00 69 00 76 00 65 | 00 74 1A 20 00 70 00 72 .r.i.v.e.t. .p.r
000030 00 69 00 76 00 65 00 74 | 00 00 1A 00 00 00 00 .i.v.e.t.......
-------------------------------------------------------------------------------
LA2: "Say2" size: 63 prot: 152 $098
Addr: Size: Type: Description: Value:
0000 2 word psz 63 | $003F
0002 1 byte ID 73 | $49 'I'
0003 58 WideString Text "pri?et priv?t prive? privet?"
003D 4 integer?? Type ALL ($00000000)

Мог бы ктонибуть подсказать в чём ошибка?

procedure GS_Encode(var buff: AnsiString; var key: AnsiString);
var
i, j, i1, sz, sk : integer;
val1: integer;
begin
sz := length(buff);
sk := length(key);
if sk < 1 then exit;
i1 := 0; j := 1;
for i := 1 to sz do begin
buff[i] := AnsiChar(ord(buff[i]) xor (ord(key[j])) xor i1);
i1 := (ord(buff[i]));
Inc(j,1);
if j > 16 then j := 1;
end;

Move(key[9], val1, 8);
val1:= val1 + sz - 2;
Move(val1, key[9], 8);
end;


Алгоритм взял из демо скриптов в wp ppc

ScythLab
20.07.2015, 16:00
Move(key[9], val1, 8);
val1:= val1 + sz - 2;
Move(val1, key[9], 8);

Как минимум нужно либо 8 на 4 заменить, либо val1 объявить как Int64 (скорей всего первый вариант).
Проверь что у тебя ключ 16 символов.
Мне непонятно зачем из sz двойка вычитается, если в GS_Encode приходят чистые данные (без длины пакета), то двойку вычитать не нужно, если в функцию приходит весь пакет вместе с длиной, то длину (первые 2 байта) кодировать не нужно.

cvillian
20.07.2015, 18:17
Мне непонятно зачем из sz двойка вычитается, если в GS_Encode приходят чистые данные (без длины пакета), то двойку вычитать не нужно.

Да точно :) Я же пример брал где алгоритм был для всего пакета с длиной и не учёл. Большое спасибо :)