PDA

Просмотр полной версии : Решил написать PH на C#.


ecl
18.06.2010, 02:50
Начал сегодня этот длинный и нелегкий путь.
Собственно на данный момент имею перехваченые пакеты в виде
масивов byte[].
С дельфи дружиться как то плохо, в плане попыток разобрать исходный код PH.
На данный момент имею несколько вопросов.
1. Что означают первые 2 байта в каждом пакете, я сравнил то что я получаю и то что отображается в PH, в пакет хаке эти 2 байта вообще не отображаются. (Вопрос отпал, это длина пакета)
2.Подскажите как можно попроще освоить синтаксис дельфи для восприятия исходиков PH.(Гугл рулит)
3.Так и не смог найти на форуме описание работы PH в плане шифровки\дешифровки.(анализ дельфийского кода + пример от alexteam на C++) Синтаксис примера arrjj труден для восприятия.

К 3ему вопросу ,насколько я понимаю это функции дешифровки,шифровки и получения ключа для для этого.
Разобраться в этом алгоритме в силу незнания delphi пока не могу, дельфийцы прокоментите пожалуйста код чтобы можно было понять алгоритм работы крипта\декрипа.



procedure L2Xor.DecryptGP(var Data; var Size: Word); // Прототип процедуры
var //Объявление переменных
k:integer; //объявление переменной типа Integer
i,t:byte; //объявление переменных типа byte
pck:array[0..$FFFD] of Byte absolute Data; //объявление масива переменных типа Integer длинной $FFFD (65533 байт) и запись в него всего пакета.
begin
i:=0; //зануление счетчика i
for k:=0 to size-1 do //начало цикла по k до конца пакета (обработка каждого байта пакета)
begin
t:=pck[k]; //Присваиваем значение текущего байта переменной t
pck[k]:=t xor GKeyR[k and keyLen] xor i xor IfThen(isAion and(k>0),Byte(KeyConst2[k and 63])); // Текущему байту пакета присваиваем значение этогоже байта отксореного на GKeyR[k and keyLen](байт ключа шифрования под номером (k and keyLen)), ксорим полученый результат на i , далее еще раз ксор если клиет=Aion(Меня Aion не интересует, пишу для себя под интерлюд шифрация стандартная)
i:=t; //Теперь устанавливаем i равным предыдущему байту, получается ксорим каждый последующий байт на GKeyR и потом еще на предыдущий байт.
end;
Inc(PCardinal(@GKeyR[keyLen-7])^,size); // Не используется пристандартной шифрации
if isAion and(Size>0)then pck[0]:=(pck[0] xor $EE) - $AE; // и нафига это... //эт для айона
end;

// На данный момент не понято:
//GKeyR[k and keyLen] - ответ дан arrjj
//Inc(PCardinal(@GKeyR[keyLen-7])^,size); - не используется при стандартном шифровании

procedure L2Xor.EncryptGP(var Data; var Size: Word);
var
i:integer;
k:byte;
pck:array[0..$FFFD] of Byte absolute Data;
begin
if isAion and(Size>0)then pck[0]:=(pck[0] + $AE) xor $EE; // и нафига это...
k:=0;
for i:=0 to size-1 do begin
pck[i]:=pck[i] xor GKeyS[i and keyLen] xor k xor IfThen(isAion and(i>0),Byte(KeyConst2[i and 63]));
k:=pck[i];
end;
Inc(PCardinal(@GKeyS[keyLen-7])^,size);
end;


Буду благодарен за любую помощ.

Спасибо.

arrjj
18.06.2010, 10:27
В синтаксисе делфи нет ничего сложного. З.Ы. могу кой-какие сорсы на с++ дать.
if isAion and(Size>0)then pck[0]:=(pck[0] + $AE) xor $EE; // и нафига это...

Шоб Аионский трафик норм пакетхаком хавался.

Инит ключа xor

switch(inptype)
{
case 0x2E://InitCrypt
{
if(!in.readC())
QMessageBox::information(NULL, "L2M Alfa:Omg",
"Wrong protocol version can be troubles :'(");
for(int x=0;x<8;x+=1)
{
inxorkey[x]=in.readC();
outxorkey[x]=inxorkey[x];
}
xorkeyaccepted=true;
out.writeC(0x2b);
l2m_mstr a;
l2m_uch tmp[28];
for(int x=0;x<28;x+=1)
tmp[x]=0;
for(int x=0;x<14;x+=1)
tmp[x*2]=ulogin[x];
a.fromuch(tmp,28);
a.killzero();
out.writeS(&a,true);
out.writeC(0x00);
out.writeD(playOK[1]);
out.writeD(playOK[0]);
out.writeD(loginOK[0]);
out.writeD(loginOK[1]);
out.writeD(0);
out.writeD(0);
out.writeD(0);
sendpacket();
}
break;
}

Расшифровка

void l2m_packets::unxorin()
{
l2m_uch tr=0;
l2m_uch tr2=0;
for(int x=0;x<in.buf.length;x+=1)
{
tr2=in.buf.str[x];
in.buf.str[x]=(tr2^inxorkey[x&15])^tr;
tr=tr2;
}
l2m_uint old = inxorkey[8] &0xff;
old |= (inxorkey[9] << 8) &0xff00;
old |= (inxorkey[10] << 0x10) &0xff0000;
old |= (inxorkey[11] << 0x18) &0xff000000;
old+=in.buf.length;
inxorkey[8] = old &0xff;
inxorkey[9] = (old >> 8) &0xff;
inxorkey[10] = (old >> 0x10) &0xff;
inxorkey[11] = (old >> 0x18) &0xff;
}

Шифровка

void l2m_packets::xorout()
{
l2m_uch tr=0;
l2m_uch tr2=0;
for(int x=0;x<out.buf.length;x+=1)
{
tr2=out.buf.str[x];
tr=tr2^outxorkey[x&15]^tr;
out.buf.str[x]=tr;
}
l2m_uint old = outxorkey[8] &0xff;
old |= (outxorkey[9] << 8) &0xff00;
old |= (outxorkey[10] << 16) &0xff0000;
old |= (outxorkey[11] << 24) &0xff000000;
old+=out.buf.length;
outxorkey[8] = old &0xff;
outxorkey[9] = (old >> 8) &0xff;
outxorkey[10] = (old >> 16) &0xff;
outxorkey[11] = (old >> 24) &0xff;
}


Имхо маешся фигнёй - зачем делать то что уже есть?

Sherman
18.06.2010, 12:08
Давно в школе стали преподавать сишарп?

ecl
18.06.2010, 12:36
Имхо маешся фигнёй - зачем делать то что уже есть?
Ну во-первых у меня нет желания работать в среде делфи.
Во-вторых интересно понимать весь процесс, а не только его малую часть.

А вообще спасибо, но жду более подробных ответов.

alexteam
18.06.2010, 12:40
гугл.

void DecryptGP(char* pck, int Size)
{
char i=0,t;
for (int k=0 ; k<Size; k++) {
t=pck[k];
pck[k]=t ^ GKeyR[k & 7] ^ i;
i=t;
}
*(int*)GKeyR+=Size;
}

void EncryptGP(char* pck, int Size)
{
pck[0]^=GKeyS[0];
for (int i=1; i<Size; i++) {
pck[i]^=GKeyS[i & 7] ^ pck[i-1];
}
*(int*)GKeyS+=Size;
}

arrjj
18.06.2010, 12:53
alexteam, это для С4 вроде

Вот хорошая статья (http://fursoffers.narod.ru/Packets.htm), правда тож немного старовата.

Ну во-первых у меня нет желания работать в среде делфи.
Во-вторых интересно понимать весь процесс, а не только его малую часть.

Чтобы понимать процесс не надо читать чужие сорсы. Да и тебя никто не заставляет в делфи работать.

alexteam
18.06.2010, 12:58
ц4 от не ц4 отличается только длинной ключа.

arrjj
18.06.2010, 13:03
alexteam, pck[k]=t ^ GKeyR[k & 7] ^ i; для ил и выше & 15(ключ длиннее) *(int*)GKeyR+=Size; для ил и выше *(int*)(GKeyR+8)+=size; - т.к. ключ меняется в другом месте.
Хотя в принципе ты прав.

ecl
18.06.2010, 13:33
гугл.

void DecryptGP(char* pck, int Size)
{
char i=0,t;
for (int k=0 ; k<Size; k++) {
t=pck[k];
pck[k]=t ^ GKeyR[k & 7] ^ i;
i=t;
}
*(int*)GKeyR+=Size;
}

void EncryptGP(char* pck, int Size)
{
pck[0]^=GKeyS[0];
for (int i=1; i<Size; i++) {
pck[i]^=GKeyS[i & 7] ^ pck[i-1];
}
*(int*)GKeyS+=Size;
}


Конечно гугл кудаж мне еще)
Я так туплю потому что C# по своей природе не работает напрямую с указателями.

Наверное по этому в голове каша... Разжуйте пожалуста что это такое

pck[k]=t ^ GKeyR[k & 7] ^ i; // ^это операция ксора а вот что это опять за злополучный GKeyR нигде не объявленый я не догоню

*(int*)GKeyR+=Size; // хз

arrjj
18.06.2010, 13:42
кеи - глобальные переменные типа char * (или char[16] как удобнее), объявляются со старта и равны
outxorkey[8] = 0xc8;
outxorkey[9] = 0x27;
outxorkey[10] = 0x93;
outxorkey[11] = 0x01;
outxorkey[12] = 0xa1;
outxorkey[13] = 0x6c;
outxorkey[14] = 0x31;
outxorkey[15] = 0x97;

Первые 8 байт считываются из пакета InitCrypt

*(int*)GKeyR+=Size; ==

unsigned int old = outxorkey[8] &0xff;
old |= (outxorkey[9] << 8) &0xff00;
old |= (outxorkey[10] << 16) &0xff0000;
old |= (outxorkey[11] << 24) &0xff000000;
old+=out.buf.length;
outxorkey[8] = old &0xff;
outxorkey[9] = (old >> 8) &0xff;
outxorkey[10] = (old >> 16) &0xff;
outxorkey[11] = (old >> 24) &0xff;

Я так туплю потому что C# по своей природе не работает напрямую с указателями.
Я тебе дал пример без указателей.

ecl
18.06.2010, 13:51
00 01 66 14 00 00 0A 7D 00 00 C8 27 93 01 A1 6C 31 97 01 00 00 00 01 00 00 00 это инит ключ отловленый пакетхаком

Расшифровка его
Tèï: 0x00 (KeyInit)
Pàçìåð: 26+2
Âðåìÿ ïðèõîäà: 12:46:02:465
0002 c 01: 1 (0x01)
0003 q Key: 137481903150182
000B d d: 26421192 (0x019327C8)

не понятно почему в твоем коде обрабатывается case 0x2E:

Если не трудно прокометни пожалуйста свой код русским языком что деается и зачем

P.S. ушел читать про протокол L2 thx.

alexteam
18.06.2010, 14:47
c4-t0
00=KeyInit:c(01)q(Key)d(d)

T1+
2E=KeyPacket:c(id 0-wrong protocol,1-protocol ok)q(key)d(01)d(ServerID)c(01)d(ObfuscationKey)

xkor
18.06.2010, 14:48
я вот как то тоже начинал писать аналог пакетхака только не для линейки а универсальный на C#, но чтот не пошло.., дальше реализации socks5 сервера дело не сдвинулось(

arrjj
18.06.2010, 14:49
Сорь, у мну для грации там (финал/эпилог), пакеты отличаются от интерлюдии

ecl
18.06.2010, 19:46
Спасибо всем.
Теперь работает крипт\декрипт пакетов.
Приступим к реализации парсера пакетов.

ecl
20.06.2010, 02:01
Провафлил я с шифрацией, на первый взгляд было все заебись да не так уж заебись оказалось=(
Дешифрую вот в такое
2D 43 76 10 48 02 00 00 07
вместо
2D 43 76 10 48 02 00 00 00 (это пакет хак дешифровал)


static public void DecryptPacket(Packet packet)
{
byte PreviousByte = 0, CurrentByte;
for (int k = 0; k < packet.Data.Length; k++)
{
CurrentByte = packet.Data[k];
packet.Data[k] = (byte)(CurrentByte ^ packet.CurrentClient.GKey[k & 15] ^ PreviousByte);
PreviousByte = CurrentByte;
}
if (packet.FromServer)
{
unchecked
{
int old = packet.CurrentClient.GKey[8] & 0xff;
old |= (packet.CurrentClient.GKey[9] << 0x08) & 0xff00;
old |= (packet.CurrentClient.GKey[10] << 0x10) & 0xff0000;
old |= (packet.CurrentClient.GKey[11] << 0x18) & (int)0xff000000;
old += packet.Size;
packet.CurrentClient.GKey[8] = (byte)(old & 0xff);
packet.CurrentClient.GKey[9] = (byte)((old >> 0x08) & 0xff);
packet.CurrentClient.GKey[10] = (byte)((old >> 0x10) & 0xff);
packet.CurrentClient.GKey[11] = (byte)((old >> 0x18) & 0xff);
}

}
}

Размер Пакета определяю из первыйх двух байт пакета.
string SizeHex = data[1].ToString("X2") + data[0].ToString("X2");
Size = int.Parse(SizeHex, NumberStyles.AllowHexSpecifier);

Вынес себе весь мозг уже не могу понять где косячу.
Help me please!

alexteam
20.06.2010, 11:47
у тебя ж ИЛ.. вроде...
а ты юзаеш ксор с т1+..

arrjj
20.06.2010, 15:16
порпобуй используй не int а unsigned int
вместо этого string SizeHex = data[1].ToString("X2") + data[0].ToString("X2");
Size = int.Parse(SizeHex, NumberStyles.AllowHexSpecifier);
лучше какнить так: Size=data[1]*0x100+data[0]; (data какнить типа unsigned char мона объявить)
Ну и чтоб посмотреть где ты ошибся - подебаж пх и посмотри как там ключ меняется и как у тебя.
alexteam, в интерлюдии также как и в грации

ecl
20.06.2010, 16:08
Оказывается увеличивать надо не на Size который записан в первых 2х байтах а на Size-2, т.е. длина пакета не учитывая длины первых двух байт с данными о размере.
+ ко всему прочему ток щас заметил что у меня некоторые пакеты приходят слипшимися, приеду с дачи буду править.

Спасибо.

arrjj
20.06.2010, 16:12
Слипшиеся/обрезанные пакеты будут приходить всегда, я решил так это:

void l2m_packets::ondata()
{
start:

if((con->bytesAvailable()<2) && (!underflow))
return;
if(!underflow)
{
l2m_uch sz[2];
sz[0]=0;
sz[1]=0;
size=0;
con->read((char*)sz,2);
size=sz[0]+sz[1]*0x100;
if(size==0)
return;
delete [] tmp_buf;
size-=2;
tmp_buf=new l2m_uch[size];
readed=con->read((char*)tmp_buf,size);
if(readed!=size)
{
underflow=true;
return;
}
}
else
{
l2m_uint readed2=0;
readed2=con->read((char*)tmp_buf+readed,size-readed);
readed+=readed2;
if(readed==size)
underflow=false;
else
return;
}
in.buffromuch(tmp_buf,size);
onpacket();
goto start;
}

ecl
21.06.2010, 04:27
А я вот так:)

void checkDataFromClientTimerCallback(object sender, EventArgs e)
{
if (SocketToClient.Available > 2)
{
bool PacketRecived = false;
MainWindow.textBoxLog.AppendText("Получен пакет от Клиента\n");
//Считываем первые 2 байта пакета и преобразоваваем их в размер пакета
byte[] CurrentPacketSize = new byte[2];
SocketToClient.Receive(CurrentPacketSize,2,SocketF lags.None);
uint CurrentPacketSizeInInt = Packet.ReadH(CurrentPacketSize, 0);
//Если Полученых данных достаточно для считывания читаем
while (!PacketRecived)
{
if (SocketToClient.Available >= CurrentPacketSizeInInt - 2)
{
//Считываем Содержимое пакета
byte[] BytesRecivedFromClient = new byte[CurrentPacketSizeInInt - 2];
SocketToClient.Receive(BytesRecivedFromClient);
PacketRecived = true;
//Создаем пакет на основе полученных данных
Packets.Add(new Packet(BytesRecivedFromClient, CurrentPacketSizeInInt, false, this));
//Шлем пакет Клиенту
byte[] PacketToSend = new byte[BytesRecivedFromClient.Length + 2];
PacketToSend[0] = CurrentPacketSize[0];
PacketToSend[1] = CurrentPacketSize[1];
for (int index = 2; index < PacketToSend.Length; index++)
{
PacketToSend[index] = BytesRecivedFromClient[index - 2];
}
SocketToServer.Send(PacketToSend);
}
Thread.Sleep(100);
}
//MainWindow.dataGridPackets.Items.Refresh();
}
}

Дешифровка пакетов в обоих направлениях наконецто работает нормально.
Парсинг тоже теперь заработал.
Завтра буду вводить еще 2 ключа GKey для подпихивания своих пакетов.

ecl
24.06.2010, 03:44
Хочу к своему пакет хаку прикрутить функцию управления клиентом из кода C#.
Конкретно:
1 Запустить клиент. (знаю как)
2 Ввести логин и пароль
3 Выбрать сервер
4 Выбрать персонажа

Подкинте пожалуйста мыслю как это можно реализовать, какие статейки можно почитать, а то я толком даже не знаю как это в поисковике в бить...

А 2й вопрос : реально ли съемулировать пакет EnterWorld? По форуму поискал нашел, но нечего толкового нет.(
Спасибо.

Добавлено через 16 минут
Хочу к своему пакет хаку прикрутить функцию управления клиентом из кода C#.
Конкретно:
1 Запустить клиент. (знаю как)
2 Ввести логин и пароль
3 Выбрать сервер
4 Выбрать персонажа

Подкинте пожалуйста мыслю как это можно реализовать, какие статейки можно почитать, а то я толком даже не знаю как это в поисковике в бить...

А 2й вопрос : реально ли съемулировать пакет EnterWorld? По форуму поискал нашел, но нечего толкового нет.(


03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C9 BC F2 A7 66 5A 0B 98 36 A5 BD 89 ED 7F E4 D7 6B 49 E2 9F EF 76 EB CE A3 FA F4 BF 0C 64 A3 B4 A4 CE DC C6 08 3E 6E EA 45 CA D3 FE 88 13 87 B8 06 2C 96 F0 9B 1E 8E BC C6 9B 98 C8 63 16 CF D0 84 67 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C9 BC F2 A7 66 5A 0B 98 36 A5 BD 89 ED 7F E4 D7 6B 49 E2 9F EF 76 EB CE A3 FA F4 BF 0C 64 A3 B4 A4 CE DC C6 08 3E 6E EA 45 CA D3 FE 88 13 87 B8 06 2C 96 F0 9B 1E 8E BC C6 9B 98 C8 63 16 CF D0 E1 4A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C9 BC F2 A7 66 5A 0B 98 36 A5 BD 89 ED 7F E4 D7 6B 49 E2 9F EF 76 EB CE A3 FA F4 BF 0C 64 A3 B4 A4 CE DC C6 08 3E 6E EA 45 CA D3 FE 88 13 87 B8 06 2C 96 F0 9B 1E 8E BC C6 9B 98 C8 63 16 CF D0 6C 3D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C9 BC F2 A7 66 5A 0B 98 36 A5 BD 89 ED 7F E4 D7 6B 49 E2 9F EF 76 EB CE A3 FA F4 BF 0C 64 A3 B4 A4 CE DC C6 08 3E 6E EA 45 CA D3 FE 88 13 87 B8 06 2C 96 F0 9B 1E 8E BC C6 9B 98 C8 63 16 CF D0 D6 2C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C9 BC F2 A7 66 5A 0B 98 36 A5 BD 89 ED 7F E4 D7 6B 49 E2 9F EF 76 EB CE A3 FA F4 BF 0C 64 A3 B4 A4 CE DC C6 08 3E 6E EA 45 CA D3 FE 88 13 87 B8 06 2C 96 F0 9B 1E 8E BC C6 9B 98 C8 63 16 CF D0 AE 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Отличаются 2мя байтами, кто знает что они отвечают?

Спасибо.

ecl
08.07.2010, 18:34
Вобщем всем кто решит идти моим путем дорога туда)
Исходники бота для линейки
http://l2net.insane-gamers.com/