PDA

Просмотр полной версии : Шифрование по алгоритму XOR


Asmoday
16.06.2009, 09:27
Доброго всем времени суток!
Начал было писать программку эмулирующую вход на сервер, но столкнулся с проблемой. Авторизацию на логин сервере прохожу вполне успежно, получаю ключи СессионИД и т.д. Загвозка заключается вот, в чем, не могу пройти логин на гейм сервере.
Часть кода взял из л2пакетхака. Пробую следующие:


const
Login='testtest';

var
XorOut, XorIn: TCodingClass;
Data:string;

....
XorIn:=L2Xor.Create;
XorOut:=L2Xor.Create;
XorIn.InitKey(Key,True);
XorOut.InitKey(Key,True);
....
Data:='08'; // RequestAuthLogin
Data:=Data+StringToHex(Login,'00')+'0000'; //Добавляем имя акка
Data:=Data+IntToHex(SessionKey2_2,8); //SessionKey2_2
Data:=Data+IntToHex(SessionKey2_1,8); //SessionKey2_1
Data:=Data+IntToHex(SessionKey1_2,8); //SessionKey1_2
Data:=Data+IntToHex(SessionKey1_1,8); //SessionKey1_1
Data:=Data+'01000000'; // Хм, что не знаю, но в пакете не изменно.
Data:=HexToStr(Data);

XorOut.EncryptGP(Data[1],Length(Data));


Сервер (и ява и птс) пишут что неверный сессион ид.
Подскажите где трабла, в чем ошибка?

И еще, я так понял, что при приеме/отправке любого пакета, ключ шифрования меняется, соответсвенно 2 вопроса:
а) Как меняется (+ или - к ключу от длинны пакета, учитываются ли те 2 байта что указывают на длунну самого пакета)
б) Учитывается ли 1 исходящий пакет ProtocolVervion и 1 входящий KeyInit при установке ключа.

Если можно немного коментов про смену ключа во время работы. Заранее благодарю.

alexteam
16.06.2009, 11:53
все пакеты вплоть(включая) до пакета иниткей идущего от гс не шифруются.
иниткей как раз и задает начальный ключ. XorIn.InitKey(Key,True);

xkor
16.06.2009, 17:36
Data:=Data+StringToHex(Login,'00')+'0000'; //Добавляем имя акка
оригинальное решение

Добавлено через 4 минуты
Data:=Data+IntToHex(SessionKey2_2,8); //SessionKey2_2
Data:=Data+IntToHex(SessionKey2_1,8); //SessionKey2_1
Data:=Data+IntToHex(SessionKey1_2,8); //SessionKey1_2
Data:=Data+IntToHex(SessionKey1_1,8); //SessionKey1_1
а вот это скорее всего и есть ошибка, ибо байты при этом разворачиваются, то есть если например SessionKey1_1 = 9, то в пакет он запишется как 00000009, а должен как 09000000

Dralka
17.06.2009, 01:45
может ктонить описать процесс XOR шифрации ?
тоже пишу софтину ...

xkor
17.06.2009, 02:30
Dralka, исходники пакетхака глянуть сложно?
http://l2phx.pp.ru/wsvn/filedetails.php?repname=l2phx3&path=%2F3.5.x%2Funits%2Fuencdec.pas - тут вот всё есть...

GoldFinch
17.06.2009, 21:48
вот так выглядит алгоритм шифрования абисса:


// код C++

#pragma pack(push,2)
struct packetbuf
{
unsigned short length;
char data[USHRT_MAX+1-2];
};
#pragma pack(pop)

class XorcryptManipulator
{
public:
XorcryptManipulator(){}
void Initialize(int key_lo,int key_hi);
opacketstream& operator() ( opacketstream& pout );
ipacketstream& operator() ( ipacketstream& pin );
private:
__int64 key_in; //key for input stream
__int64 key_out; //key for output stream
};


opacketstream& bot::XorcryptManipulator::operator()( opacketstream& pout )
{
packetbuf& buf=pout.buffer();
union
{
__int64 key;
char bytes[8];
} k2;
k2.key=key_out;

char k;
buf.data[0] ^= k2.bytes[0];
for (int i=1;i<buf.length;++i,buf.data[i-1]^=k)
k=k2.bytes[i&7] ^ buf.data[i-1];

key_out += buf.length;
return pout;
}

ipacketstream& bot::XorcryptManipulator::operator()( ipacketstream& pin )
{
packetbuf& buf=pin.buffer();
union
{
__int64 key;
char bytes[8];
} k2;
k2.key=key_in;

char k=buf.data[0];
buf.data[0] ^= k2.bytes[0];
for(int i=1;i<buf.length;++i)
{
char t=buf.data[i];
buf.data[i]^=k^k2.bytes[i&7];
k=t;
}

key_in += buf.length;
return pin;
}

void bot::XorcryptManipulator::Initialize( int key_lo,int key_hi )
{
union
{
__int64 key;
struct
{
int lo;
int hi;
};
} k;
k.lo=key_lo;
k.hi=key_hi;
key_in=k.key;
key_out=k.key;
}

roma_
03.09.2009, 22:31
Сразу прошу прощение за навязчивость но попрошу описать алгоритм смены XOR ключа, точнее алгоритм получения начального xor ключа.
Если вдруг кто нить решится то БОЛЬШАЯ просьба описать в виде операций, на примере.

Исходники смотрел но разобраться в паскале не смог :( учил си

Добавлено через 10 минут
уточнение - клиент С4

alexteam
03.09.2009, 22:54
алгоритм получения начального xor ключа
уточнение - клиент С4
часть ключа - статическая (4 байта), а часть - приходит от сервера с пакетом 2Eh (тоже 4 байта)
склеиваем и получаем ключ котором следует ксорить/дексорить данные идущие после иниткея.
по ссылке которую выше давал xkor смотреть
L2Xor.InitKey и концовку TencDec.ProcessRecivedPacket

roma_
04.09.2009, 01:10
Еще раз спасибо alexteam за ответ.

Алгоритм примерно понял, помогите разобраться каким образом L2PacketHack получает НАЧАЛЬНЫЙ XOR ключ для дешифровки первого пакета?

пакет с ключем KeyInit
0001 03 B1 93 B6 01 00 00 00 01 00 00 00

следующий пакет (еще не дешифрован)
17 E8 E0 E0 02 12 AE F0 F4 43 4B 05 E7 EA 56 5A 5E....

этот же пакет но после дешифровки L2PacketHack
13 01 00 00 43 7C E8 D9 00 49 00 4E 43 61 E8 8B 00....

восстанавливаю XOR ключ, получаю:
04 FE 08 00 A1 6C 54 87 04

байты с 5 по 8 понятно, это константный ключ, а вот первые четыре совсем не совпадают с ключом из пакета KeyInit

как получился такой ключ?

Добавлено через 1 час 48 минут
Эта процедура формирует начальный XOR ключ?
я в паскале ничего не понимаю :(

procedure TencDec.CorrectXor;
var
// tmp: string;
Offset: Word;
TempPacket : Tpacket;
begin
//Обход смены XOR ключа.
case pckCount of
3: CorrectXorData := Packet;
4: begin
TempPacket := Packet;
// SetLength(tmp, TempPacket.Size);
// Move(TempPacket, tmp[1], TempPacket.Size);
xorS.DecryptGP(TempPacket.Data, TempPacket.Size-2);
Offset := $13 or ((TempPacket.size-7) div 295) shl 8;
PInteger(@TempPacket.Data[0])^:=PInteger(@TempPacket.Data[0])^ xor Offset xor PInteger(@(xorS.GKeyS[0]))^;
xorS.InitKey(TempPacket.Data[0],isInterlude);
xorC.InitKey(TempPacket.Data[0],isInterlude);
if (not Settings.isNoDecrypt) then xorC.DecryptGP(CorrectXorData.Data, CorrectXorData.Size-2);
if (not Settings.isNoDecrypt) then xorC.EncryptGP(CorrectXorData.Data, CorrectXorData.Size-2);
InitXOR:=True;
end;
end;
end;

Если да, то пожалуйста ответьте на вопросы:
1)
TempPacket.size это размер четвертого пакета? (в котором передаются данные о выбранном персонаже)?

2) откомментируйте чего происходит в этих строках

PInteger(@TempPacket.Data[0])^:=PInteger(@TempPacket.Data[0])^ xor Offset xor PInteger(@(xorS.GKeyS[0]))^;
xorS.InitKey(TempPacket.Data[0],isInterlude);
xorC.InitKey(TempPacket.Data[0],isInterlude);
if (not Settings.isNoDecrypt) then xorC.DecryptGP(CorrectXorData.Data, CorrectXorData.Size-2);
if (not Settings.isNoDecrypt) then xorC.EncryptGP(CorrectXorData.Data, CorrectXorData.Size-2);

xkor
04.09.2009, 01:31
а часть - приходит от сервера с пакетом 2Eh (тоже 4 байта)2Eh это начиная с камаэля где то, а в С4 этот пакет был с ИД - 0

roma_, странно что ключ неверный, он отличается от стандартно полученного, CorrectXor насколько я помню получает ключ (текущий а не начальный) анализируя толи 4й толи 3й пакет (поскольку там всегда нули в том месте которое шифруется динамической частью ключа, то можно вычислить текущий ключ)

roma_
04.09.2009, 03:41
странно что ключ неверный

L2PacketHack вычислил правильный ключ, пакеты расшифровывает верно.
Только мне не понятен алгоритм получения им этого ключа, которым он расшифровывает 1й зашифрованный пакет от сервера.

Вот пакет с ключем KeyInit, он не шифруется
0001 03 B1 93 B6 01 00 00 00 01 00 00 00

03 B1 93 B6 - это первая часть ключа, вторая A1 6C 54 87 - это константа
в итоге получается такой ключ: 03 B1 93 B6 A1 6C 54 87

Но L2PacketHack первый пакет от сервера расшифровывал этим ключом:
04 FE 08 00 A1 6C 54 87

Вот я и пытаюсь понять как он из получил 04 FE 08 00 этот ключ
Полагаю что работает смена XOR ключа, опция в настройках включена.
Остальные ключи получаются добавлением длины пакета к текущему ключу.
А вот как и по какому алгоритму получается ключ для первого зашифрованного пакета?
Т.е. этот 04 FE 08 00

Добавлено через 1 минуту
С паскалем у меня проблемы, пишу на С++
Поэтому из исходников паскаля и не могу разобраться с алгоритмом :(

xkor
04.09.2009, 04:16
вот весь алгоритм:
Offset := $13 or ((TempPacket.size-7) div 295) shl 8;
PInteger(@TempPacket.Data[0])^:=PInteger(@TempPacket.Data[0])^ xor Offset xor PInteger(@(xorS.GKeyS[0]))^;

это для пакета со списком чаров (первый зашифрованный пакет от сервера)
тут в Offset заносится количество чаров на аке во второй байт (вычисляется исходя из размера пакета), и id пакета ($13) в первый байт
тока перед всеми этими операция дешифруем неверным ключем
а дальше чтобы получить ключ настоящий ксорим первые 4 байта пакета на Offset и на первые 4 байта неверного ключа

alexteam
04.09.2009, 11:45
xkor, пардон.
тогда смотреть
L2Xor.InitKey и начало TencDec.ProcessRecivedPacket ;)

Эта процедура формирует начальный XOR ключ?
я в паскале ничего не понимаю
L2Xor.InitKey его формирует.
InitKey вызывается из ProcessRecivedPacket после прихода 00h/2Eh
ну.. стоит оговориться что это в идеальном случае..
в твоем я так понимаю используеться CorrectXor


procedure TencDec.CorrectXor;
var
Offset: Word;
TempPacket : Tpacket;
begin
//Обход смены XOR ключа.
case pckCount of //В зависимости от номера пакета
3: CorrectXorData := Packet; //3й по счету пакет в "сеансе связи" мы запоминаем
4: begin //и используем тут
TempPacket := Packet;
xorS.DecryptGP(TempPacket.Data, TempPacket.Size-2);
Offset := $13 or ((TempPacket.size-7) div 295) shl 8;//получаем ключ ориентируясь на 4й и запомненный 3й пакет предварительно "продекриптив" 4й пакет. и попутно привев его к изначальному (?) виду.
PInteger(@TempPacket.Data[0])^:=PInteger(@TempPacket.Data[0])^ xor Offset xor PInteger(@(xorS.GKeyS[0]))^;

xorS.InitKey(TempPacket.Data[0],isInterlude); //собственно в TempPacket.Data[0] лежит наш ключик.
xorC.InitKey(TempPacket.Data[0],isInterlude);

//чтобы всем было хорошо и в кеях у нас лежали "правильные" ключики, "учитываем" 4й пакет %)
if (not Settings.isNoDecrypt) then xorC.DecryptGP(CorrectXorData.Data, CorrectXorData.Size-2);
if (not Settings.isNoDecrypt) then xorC.EncryptGP(CorrectXorData.Data, CorrectXorData.Size-2);
InitXOR:=True;
end;
end;
end;

roma_
04.09.2009, 15:33
Спасибо за оказанную помощь, пошел проверять :)