Платформа: HighFive, Ревизия протокола: c621 (согласно TechnoWiz@rd)
Основные методы:
Оффтоп
Код:
const
MAX_PKT_SIZE = $FFFF;
var
BLOWFISH_KEY: String; { 6B60CB5B82CE90B1CC2B6C556C6C6C6C }
MainBuff: array[0..MAX_PKT_SIZE-1] of byte;
RecvPktCount: Integer;
DecodeBF: boolean;
L2BF: L2BlowFish;
L2BF_Key: String;
RSA_Key: String;
SessionID: Integer;
GGAuthResponse: Integer;
SessionKey1_1, SessionKey1_2: Integer;
SessionKey2_1, SessionKey2_2: Integer;
procedure TfrmMain.WMSOCK_RS_EVENT(var Msg: TMessage);
var
SocketError: Integer;
Len: Integer;
begin
SocketError := WSAGetSelectError(Msg.lParam);
if (SocketError<>0) then begin
if SocketError=10053 then
ToLog('[WMSOCK_RS_EVENT]: WSAECONNABORTED (#10053) - Software caused connection abort')
else
ToLog('[WMSOCK_RS_EVENT]: WS_ERROR (#number): '+IntToStr(SocketError));
ToLog('');
L2SocketClose(RS_Socket);
Exit;
end;
case WSAGetSelectEvent(Msg.lParam) of
FD_Read:
begin
FillChar(MainBuff, Length(MainBuff), 0);
Len := recv(RS_Socket, MainBuff, MAX_PKT_SIZE, 0);
inc(RecvPktCount);
LS_Parser(MainBuff, Len);
end;
FD_Close:
L2SocketClose(RS_Socket);
end;
end;
procedure TfrmMain.LS_Parser(buff: Array of Byte; Len: Integer);
var
temp: array [0..MAX_PKT_SIZE-1] of char;
s: string;
i: integer;
begin
if RecvPktCount=1 then
begin
if buff[2]=0 then
DecodeBF := False
else
DecodeBF := True;
end;
if DecodeBF then
begin
Move(buff[2],temp[0],Len-2);
L2BF.bfDecode(temp,Len-2);
if temp[0]=#0 then
begin
SetLength(s,Len-2);
for i:=0 to Len-3 do
s[i+1]:=temp[i];
s:=AntiXor(s);
for i:=0 to Len-3 do
temp[i]:=s[i+1];
end;
Move(temp[0],buff[2],Len-2);
end;
PacketView(buff,Len,True);
case buff[2] of
$00:
LS_Init(buff,Len);
$0B:
LS_GGAuth(buff,Len);
$01:
LS_LoginFail(buff,Len);
$03:
LS_LoginOk(buff,Len);
$04:
LS_ServerList(buff,Len);
$06:
LS_PlayFail(buff,Len);
$07:
LS_PlayOk(buff,Len);
end;
end;
Порядок авторизации на Login-Server:
1)
Init().................................................. .[
OK] { Server->Client }
Оффтоп
Код:
procedure TfrmMain.LS_Init(buff: array of byte; Len: integer);
begin
if Len<8 then exit;
Move(buff[3], SessionID, 4);
if Len>=155 then
begin
SetLength(RSA_key,128);
Move(buff[11],RSA_key[1],128); { RSA Key changed }
end;
if Len>=171 then
begin
SetLength(L2BF_key,16);
Move(buff[155],L2BF_key[1],16); { BlowFish Key changed }
L2BF.Init(L2BF_key);
end;
end;
{ sending RequestGGAuth packet }
RequestGGAuth();
2)
RequestGGAuth()..................................[
OK] { Client->Server }
Оффтоп
Код:
procedure TfrmMain.RequestGGAuth;
var
Data: array[0..39] of byte;
begin
FillChar(data, Length(data), 0);
data[0]:=7;
Move(SessionID, data[1], 4);
AddCheckSumm(data, 24);
PacketSend(data, 40);
end;
3)
LS_GGAuth().........................................[
OK] { Server->Client } сервер ответил, что авторизация на GG прошла успешно
Оффтоп
Код:
procedure TfrmMain.LS_GGAuth(buff: array of byte; Len: integer);
begin
if Len>=7 then
Move(buff[3], GGAuthResponse, 4);
RequestAuthLogin(Login, Password);
end;
4)
RequestAuthLogin()...............................[
OK] { Client->Server } клиент отправляет Логин и Пароль
Оффтоп
Код:
procedure TfrmMain.RequestAuthLogin(_login, _password: string);
var
data: array[0..175] of byte;
crypt_text: string;
begin
FillChar(data,Length(data),0);
crypt_text := RSAEncrypt(_login, _password, RepairKey(RSA_key));
Move(crypt_text[1], data[1], 128);
Move(GGAuthResponse, data[129], 4);
data[149]:=8;
AddCheckSumm(Data, 160);
PacketSend(Data, 176);
end;
5)
LoginOK().............................................[
OK] { Server->Client } проверка Логина и Пароля прошла успешно, +Session_Key_1
Оффтоп
Код:
procedure TfrmMain.LS_LoginOk(buff: array of byte; Len: integer);
begin
if Len<12 then exit;
ToLog('[LS_LoginOk]: Login Successful!');
ToLog('');
Move(buff[3],SessionKey1_1,4);
Move(buff[7],SessionKey1_2,4);
RequestServerList();
end;
6)
RequestServerList()..............................[
FAIL] { Client->Server }
Оффтоп
Код:
procedure TfrmMain.RequestServerList();
var
data: array[0..31] of byte;
begin
FillChar(data, Length(data), 0);
data[0] := 5;
Move(SessionKey1_1, data[1], 4);
Move(SessionKey1_2, data[5], 4);
data[9] := 4;
AddCheckSumm(data, 16);
PacketSend(data, 32);
DecodeBF := TRUE;
end;
Далее описывать код пока не буду - до тех пунктов даже не доходит программа
7)
ServerList()..........................................[
NoNe] { Server->Client } передается список рабочих серверов
8)
RequestServerLogin()............................[
NoNe] { Client->Server } запрос игры на выбранном сервере
9)
PlayOK()..............................................[
NoNe] { Server->Client } подключение к Game-Server разрешено, +Session_Key_2
Лог выполнения программы -
L2Connect_Log.txt
Вопросы:
1) Ну раз программа прошла GGAuth и LoginOK значит с шифрованием все нормально: иначе бы в методе
LS_Parser программа не смогла бы определить тип пакета (
[LS_Parser]: buff[2]=0x0B ) и не продвинулась бы дальше по цепочке. Что не так в пакете
RequestServerList? в упор не пойму, где я ошибся