Пользователь
Регистрация: 29.07.2013
Сообщений: 309
Отблагодарили 69 раз(а)
|
Re: Строим эмулятор B&S emulator from scratch
Хотя интерес к данной теме угас значительно, все-таки решил продолжить ее наполнение. Перед тем, как преступить к изложению концепции системы крипта, который мы использовали, хочу выразить свое негодование по поводу идиотов, которые критикуют код и пишут болдом в каждой теме. Ни о каком уважении речь идти не может. О таких гуру кодертсва могу сказать одно - конченные.
Для отсальных скажу лишь то, что код атомикса выдерживал онлайн в 3к человек и выдерживал его стабильно. Поэтому если хотите убедить меня в том, что наш код плохой, напишите свой сервер без наших наработок и протестируйте его на живом онлайне.
Свернуть ↑
На данном этапе я препологаю, что у вас уже имеется рабочая система БД и аккаунтов, а также рабочий логин сервер.
Свернуть ↑
Сетевой крипт для лобби и гейм сервера представляет собой систему RSA с публичным и приватным ключем. Кто-то говорит что нет, кто-то говорит что да. Но единного мнения нету. Лично я считаю, что это все-таки RSA который сверху закодированный AES. Спорить не буду, поскольку система рабочая.
Для того чтобы расшифровать пакеты лобби сервера, нам понадобится пара ключей, хэндшейк и AES ключ, который генерируется вместе с остальными ключами, которые идут зашифрованные в пакете.
Проще говоря нам нужны 2 пакета и 1 AES ключ от конкретной сессии. Каждый АES ключ привязан только к 1 сессии, т.е. после релогина вы не сможете зайти повторно, придется перезагружать игру, чтобы открыть первую сессию.
Данные пакеты передаются первыми, так мы узнаем о том, что они несут в себе обмен ключами.
Свернуть ↑
От сервера:
404091DDC3566EFFB22973837A0E135FBA3EE5DC67E0850D7AFA8CA743F3764DA2EA428B338A24B11855EDC2AE7E72C3FEA4BECBFE905B537EFE38430B7C68C43F697AC23A7996E16D5D4766BCC352B86D733218DA0604B598EC14932A986AAC910A2FB31F595CD7CD4AB43CFF5CF1C9262760F57DAB453EC816CB366BD0D30FB81F7E05650AF15CE7BFE341BA7D91F4C4F3D3754C937CCF118DEE60F8260AA3B4AEB101BDD1772EC8953CFCCFB150651A9198D0DB2CACA09279CABD18518DAA1E42B429168D4CE9848FE294BF3FF28D35E09CE6DC914613A6F61AB6F4541E6F42FC2D165492879424FED57E2B69BC9854DF2AB2F46A28D6E0A0495E352100F7B72DCode: C++ От клиента:
10500CC457B8CBBEA528768F06CCED65A1123C100E8D9529829540C186D7084CF2475D9E3B386E8AE8ADD23E0534170685FDEA62095A29F2F6B7C9C9A7E9A9BD8974Code: C++ AES ключ:
09CE3091EC409BAE5649A336C43CBA74Code: C++ Этот метод называется подменой ключей. Истиного RSA у нас никогда не было.
Если вам, гуру и джежаем этот метод не нравится - реверсите клиент до той степени, пока не получите полноценный крипт. Я уделил этому много времени, увы и ах.
Свернуть ↑Развернуть ↓
Свернуть ↑
Следующий код, демонстрирует процесс подмены ключей:
Ключи можно хранить в XML документе в конфигах.
<!-- Настройка AES ключа для шифрования траффика -->
<EncryptionKeyPair handshake="404091DDC3566EFFB22973837A0E135FBA3EE5DC67E0850D7AFA8CA743F3764DA2EA428B338A24B11855EDC2AE7E72C3FEA4BECBFE905B537EFE38430B7C68C43F697AC23A7996E16D5D4766BCC352B86D733218DA0604B598EC14932A986AAC910A2FB31F595CD7CD4AB43CFF5CF1C9262760F57DAB453EC816CB366BD0D30FB81F7E05650AF15CE7BFE341BA7D91F4C4F3D3754C937CCF118DEE60F8260AA3B4AEB101BDD1772EC8953CFCCFB150651A9198D0DB2CACA09279CABD18518DAA1E42B429168D4CE9848FE294BF3FF28D35E09CE6DC914613A6F61AB6F4541E6F42FC2D165492879424FED57E2B69BC9854DF2AB2F46A28D6E0A0495E352100F7B72D">
<Key exchangekey="10500CC457B8CBBEA528768F06CCED65A1123C100E8D9529829540C186D7084CF2475D9E3B386E8AE8ADD23E0534170685FDEA62095A29F2F6B7C9C9A7E9A9BD8974">
09CE3091EC409BAE5649A336C43CBA74
</Key>
</EncryptionKeyPair>Code: XML case "encryptionkeypair":
{
string handshake = i.Attributes[0].Value.Substring(260);
XmlNodeList children = i.ChildNodes;
foreach (object l in children)
{
XmlElement k = l as XmlElement;
if (k == null) continue;
switch (k.Name.ToLower())
{
case "key":
byte[][] keypair = new byte[2][];
keypair[0] = Conversions.HexStr2Bytes(k.Attributes[0].Value);
keypair[1] = Conversions.HexStr2Bytes(k.InnerText.Replace("\r","").Replace("\n","").Replace(" ",""));
Base.BNSGameNetwork<Base.Packets.LobbyPacketOpcode>.AddKeyPair(handshake, keypair);
break;
}
}
}Code: C++ Далее переходим к процедуре AddKeyPair и создания сокета для получения и расшифровки пакетов:
public class BNSGameNetwork<T> : Network<T>
{
bool ready = false;
static Dictionary<string, List<byte[][]>> ExchangeKeys =new Dictionary<string,List<byte[][]>>();
public static void AddKeyPair(string handshake, byte[][] keypair)
{
if (!ExchangeKeys.ContainsKey(handshake))
ExchangeKeys.Add(handshake, new List<byte[][]>());
ExchangeKeys[handshake].Add(keypair);
}
public byte[] ExchangeKey;
public override Network<T> CreateNewInstance(System.Net.Sockets.Socket sock, Dictionary<T, Packet<T>> commandTable, Session<T> client)
{
BNSGameNetwork<T> instance = new BNSGameNetwork<T>();
CreateNewInstance(instance, sock, commandTable, client);
return instance;
}
protected override void OnReceivePacket(byte[] buf)
{
if (ready)
{
int totalLen = BitConverter.ToInt16(buf, 0);
totalLen = (totalLen & 0xfff) * 4;
if (buf.Length - 2 >= totalLen)
{
try
{
byte[] buf2 = new byte[totalLen];
Array.Copy(buf, 2, buf2, 0, totalLen);
Crypt.Decrypt(buf2, 0, totalLen);
int len = BitConverter.ToInt16(buf2, 0) - 2;
byte[] tmp = new byte[len];
Array.Copy(buf2, 2, tmp, 0, len);
Packet<T> p = new Packet<T>();
p.PutBytes(tmp, 0);
ProcessPacket(p);
if (totalLen < buf.Length - 2)
{
int rest = buf.Length - 2 - totalLen;
buf2 = new byte[rest];
Array.Copy(buf, totalLen + 2, buf2, 0, rest);
OnReceivePacket(buf2);
}
else
lastContent = null;
}
catch (Exception)
{
}
}
else
lastContent = buf;
}
else
{
string handshake = Conversions.bytes2HexString(buf);
List<byte[][]> list;
if (ExchangeKeys.TryGetValue(handshake.Substring(260), out list))
{
byte[][] keypair = list[Global.Random.Next(0, list.Count - 1)];
ExchangeKey = keypair[0];
((Base.Encryption.BNSAESEncryption)Crypt).Key = keypair[1];
SendExchangePacket();
}
else
{
Logger.ShowWarning(string.Format("Не удается найти пару ключа:{0}", handshake));
Disconnect();
}
}
}
public void SendExchangePacket()
{
SendPacketRaw(ExchangeKey, 0, ExchangeKey.Length);
ready = true;
}Code: C++ Для работы данного кода, понадобится зависимый класс для расшифровки AES ключа:
public class BNSAESEncryption : KOI.Network.Encryption
{
Rijndael aes;
public byte[] Key;
ICryptoTransform enc;
ICryptoTransform dec;
public BNSAESEncryption()
{
aes = Rijndael.Create();
aes.Mode = CipherMode.ECB;
enc = aes.CreateEncryptor(Key, new byte[16]);
dec = aes.CreateDecryptor(Key, new byte[16]);
}
public override KOI.Network.Encryption Create()
{
return new BNSAESEncryption();
}
public override void Encrypt(byte[] src, int offset, int len)
{
enc = aes.CreateEncryptor(Key, new byte[16]);
enc.TransformBlock(src, offset, len, src, offset);
}
public override void Decrypt(byte[] src, int offset, int len)
{
byte[] buf = new byte[len + 16];
dec = aes.CreateDecryptor(Key, new byte[16]);
src.CopyTo(buf, 0);
dec.TransformBlock(buf, offset, len + 16, buf, offset);
Array.Copy(buf, offset, src, offset, len);
}
}
}Code: C++ Вот в кратце и все что вам нужно знать, для расшифровеи траффика. Ключи приведенные здесь 100% проверенные и будут работать до тех пор, пока система лобби не будет изменена в корне. А поскольку она не меняется с ЗБТ3, то и ключи также не меняются.
У вас может возникнуть один вопрос. Откуда взять AES ключи, поскольку они открывают сессию и являются основным элементом крипта.
Ответ: из olly. И пожалуй оставлю в секрете алгоритм получения их.
Свернуть ↑Развернуть ↓
Свернуть ↑Развернуть ↓
Свернуть ↑
Поскольку мы используем свою сетевую модель, длина данных будет обозначаться следующим образом:
Параметры GET/SET думаю всем понятно да?
Тип данных:
Byte - понятно 1 байт
Short/Ushort - 2 байта
Int/Uint - 4 байта
Long/Ulong - 8 байтов.
Выражение GetUshort(18) в нашей моделе означает, мы считываем 2 байта с 18 позиции следования. Если пакет имеет вид 01 00 00 00 01 то выражение GetUshort(2) означает что читаем следующие два байта 01 00 00 00 01. Надеюсь понятно.
Погнали:
Свернуть ↑
public class SM_CHAR_CREATE : Packet<LobbyPacketOpcode>
{
ushort marker = 0;
ushort marker2 = 0;
public SM_CHAR_CREATE()
{
this.ID = LobbyPacketOpcode.SM_CHAR_CREATE;
}
public ActorPC Character
{
set
{
PutBytes(Utils.slot2GuidBytes(value.SlotID));
PutUShort(value.WorldID);
PutShort((short)value.Name.Length);
PutBytes(Encoding.Unicode.GetBytes(value.Name));
marker = offset;
PutShort(0);//length
PutShort(0);//length
PutUShort((ushort)value.Appearence1.Length);
PutBytes(value.Appearence1);
//Race ID
PutUShort(0);
PutByte((byte)value.Race);
//Gender ID
PutUShort(1);
PutByte((byte)value.Gender);
//Class ID
PutUShort(2);
PutByte((byte)value.Job);
//Appearence ID
PutUShort(3);
PutUShort((ushort)value.Appearence2.Length);
PutBytes(value.Appearence2);
//Name ID
PutUShort(4);
PutBytes(Encoding.Unicode.GetBytes(value.Name));
PutShort(0);//Terminator for String
//Unknown ID
PutUShort(5);
PutUShort(0);
//Map ID
PutUShort(6);
PutUInt(value.MapID);
//X ID
PutUShort(7);
PutShort((short)value.X);
//Y ID
PutUShort(8);
PutShort((short)value.Y);
//Z ID
PutUShort(9);
PutShort((short)value.Z);
//Level ID
PutUShort(10);
PutByte(value.Level);
//Unknown ID
PutUShort(11);
PutUInt(0);
//Health Points ID
PutUShort(12);
PutInt(value.MaxHP);
//Unknown ID
PutUShort(13);
PutUShort(0);
//Gold ID
PutUShort(14);
PutInt(value.Gold);
//Weapon ID
PutUShort(15);
//if (value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.Weapon] != null)
// PutUInt(value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.Weapon].ItemID);
//else
PutUInt(0);
//Unknown ID
PutUShort(16);
PutUInt(0);
//Costume ID
PutUShort(17);
//if (value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.Costume] != null)
// PutUInt(value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.Costume].ItemID);
//else
PutUInt(0);
//Unknown ID
PutUShort(18);
PutUInt(0);
//Eye Accessory ID
PutUShort(19);
//if (value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.Eye] != null)
// PutUInt(value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.Eye].ItemID);
//else
PutUInt(0);
//Hat ID
PutUShort(20);
//if (value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.Hat] != null)
// PutUInt(value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.Hat].ItemID);
//else
PutUInt(0);
//Costume Accessory ID
PutUShort(21);
//if (value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.CostumeAccessory] != null)
// PutUInt(value.Inventory.Equipments[Base.Inventory.InventoryEquipSlot.CostumeAccessory].ItemID);
//else
PutUInt(0);
marker2 = offset;
PutUShort((ushort)(marker2 - (marker + 2)), marker);
PutUShort((ushort)(marker2 - (marker + 2)));
offset = marker2;
PutInt(0);
PutInt(0);
PutInt(0);
PutInt(0);
}
}
}Code: C++ public class CM_CHAR_CREATE : Packet<LobbyPacketOpcode>
{
public CM_CHAR_CREATE()
{
this.ID = LobbyPacketOpcode.CM_CHAR_CREATE;
}
public ActorPC Character
{
get
{
ActorPC pc = new ActorPC();
byte[] guid = GetBytes(16, 2);
for (int i = 0; i < 10; i++)
{
if (Conversions.bytes2HexString(guid).Equals(Conversions.bytes2HexString(Utils.slot2GuidBytes(i))))
{
pc.SlotID = (byte)i;
break;
}
}
pc.WorldID = (byte)GetUShort(18);
pc.Name = Encoding.Unicode.GetString(GetBytes((ushort)(GetUShort(20) * 2)));
offset += 4;
pc.Appearence1 = Conversions.HexStr2Bytes(Conversions.bytes2HexString(GetBytes(GetUShort())) + "7364777777636464776464646464646464");
offset += 2;
pc.Race = (Race)GetByte();
offset += 2;
pc.Gender = (Gender)GetByte();
offset += 2;
pc.Job = (Job)GetByte();
offset += 2;
pc.Appearence2 = GetBytes(GetUShort());
//Outside Packet
pc.Level = 1;
pc.MapID = 1101;
pc.X = -3177;
pc.Y = 9243;
pc.Z = 599;
pc.Dir = 45;
pc.UISettings = "";
pc.InventorySize = 32;
pc.HP = 99;
pc.MaxHP = 99;
switch (pc.Job)
{
case Job.Assassin:
pc.MP = 0;
pc.MaxMP = 10;
break;
case Job.ForceMaster:
pc.MP = 10;
pc.MaxMP = 10;
break;
case Job.KungfuMaster:
pc.MP = 0;
pc.MaxMP = 10;
break;
case Job.BladeMaster:
default:
pc.MP = 0;
pc.MaxMP = 10;
break;
}
return pc;
}
}
public override Packet<LobbyPacketOpcode> New()
{
return new CM_CHAR_CREATE();
}
public override void OnProcess(Session<LobbyPacketOpcode> client)
{
((LobbySession)client).OnCharCreate(this);
}
}Code: C++
Свернуть ↑Развернуть ↓
Свернуть ↑
public class CM_CHAR_DELETE : Packet<LobbyPacketOpcode>
{
public CM_CHAR_DELETE()
{
this.ID = LobbyPacketOpcode.CM_CHAR_DELETE;
}
public byte[] Guid
{
get
{
return GetBytes(16, 2);
}
}
public override Packet<LobbyPacketOpcode> New()
{
return new CM_CHAR_DELETE();
}
public override void OnProcess(Session<LobbyPacketOpcode> client)
{
((LobbySession)client).OnDeleteChar(this);
}
}Code: C++ public class SM_CHAR_DELETE : Packet<LobbyPacketOpcode>
{
public enum Reasons
{
Okay = 0,
}
public SM_CHAR_DELETE()
{
this.ID = LobbyPacketOpcode.SM_CHAR_DELETE;
}
public byte[] SlotGuid
{
set
{
PutBytes(value, 2);
}
}
public Reasons Reason
{
set
{
PutByte(0,18);
PutInt((int)value);
}
}
}Code: C++
Свернуть ↑Развернуть ↓
Свернуть ↑
public class SM_CHARACTER_LIST : Packet<LobbyPacketOpcode>
{
ushort marker = 0;
ushort marker2 = 0;
public SM_CHARACTER_LIST()
{
this.ID = LobbyPacketOpcode.SM_CHARACTER_LIST;
}
public List<ActorPC> Characters
{
set
{
PutUShort((ushort)value.Count, 6);
foreach (ActorPC i in value)
{
PutBytes(Utils.slot2GuidBytes(i.SlotID));
PutUShort(i.WorldID);
PutShort((short)i.Name.Length);
PutBytes(Encoding.Unicode.GetBytes(i.Name));
marker = offset;
PutShort(0);//length
PutShort(0);//length
PutUShort((ushort)i.Appearence1.Length);
PutBytes(i.Appearence1);
//Race ID
PutUShort(0);
PutByte((byte)i.Race);
//Gender ID
PutUShort(1);
PutByte((byte)i.Gender);
//Class ID
PutUShort(2);
PutByte((byte)i.Job);
//Appearence ID
PutUShort(3);
PutUShort((ushort)i.Appearence2.Length);
PutBytes(i.Appearence2);
//Name ID
PutUShort(4);
PutBytes(Encoding.Unicode.GetBytes(i.Name));
PutShort(0);//Terminator for String
//Unknown ID
PutUShort(5);
PutUShort(0);
//Map ID
PutUShort(6);
PutUInt(i.MapID);
//X ID
PutUShort(7);
PutShort((short)i.X);
//Y ID
PutUShort(8);
PutShort((short)i.Y);
//Z ID
PutUShort(9);
PutShort((short)i.Z);
//Level ID
PutUShort(10);
PutByte(i.Level);
//Unknown ID
PutUShort(11);
PutUInt(0);
//Health Points ID
PutUShort(12);
PutInt(i.MaxHP);
//Unknown ID
PutUShort(13);
PutUShort(0);
//Gold ID
PutUShort(14);
PutInt(i.Gold);
//Weapon ID
PutUShort(15);
if (i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.hand - 1] != null)
PutUInt(i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.hand - 1].ItemID);
else
PutUInt(0); //Equip Hand
//Alternate Hand
PutUShort(16);
PutUInt(0);
//Costume ID
PutUShort(17);
if (i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.body - 1] != null)
PutUInt(i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.body - 1].ItemID);
else
PutUInt(0);//Equip Body
//Ear
PutUShort(18);
PutUInt(0);
//Eye Accessory ID
PutUShort(19);
if (i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.eye - 1] != null)
PutUInt(i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.eye - 1].ItemID);
else
PutUInt(0);//Equip Eye
//Hat ID
PutUShort(20);
if (i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.head - 1] != null)
PutUInt(i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.head - 1].ItemID);
else
PutUInt(0);//Equip Head
//Costume Accessory ID
PutUShort(21);
if (i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.body_attach - 1] != null)
PutUInt(i.Inventory.Container[Containers.Equipment][(int)InventoryEquipSlot.body_attach - 1].ItemID);
else
PutUInt(0);//Equip Body Attach
marker2 = offset;
PutUShort((ushort)(marker2 - (marker + 2)), marker);
PutUShort((ushort)(marker2 - (marker + 2)));
offset = marker2;
PutInt(0);
PutInt(0);
PutInt(0);
PutByte(0);
}
PutUInt((uint)offset - 6, 2);
}
}
}Code: C++ public class CM_CHARACTER_LIST : Packet<LobbyPacketOpcode>
{
public CM_CHARACTER_LIST()
{
this.ID = LobbyPacketOpcode.CM_CHARACTER_LIST;
}
public override Packet<LobbyPacketOpcode> New()
{
return new CM_CHARACTER_LIST();
}
public override void OnProcess(Session<LobbyPacketOpcode> client)
{
((LobbySession)client).OnCharacterList(this);
}
}Code: C++
Свернуть ↑Развернуть ↓
Свернуть ↑
public class SM_REQUEST_LOGIN : Packet<LobbyPacketOpcode>
{
public SM_REQUEST_LOGIN()
{
this.ID = LobbyPacketOpcode.SM_REQUEST_LOGIN;
}
public ulong CharID
{
set
{
PutULong(value, 2);
}
}
}Code: C++ public class CM_REQUEST_LOGIN : Packet<LobbyPacketOpcode>
{
public CM_REQUEST_LOGIN()
{
this.ID = LobbyPacketOpcode.CM_REQUEST_LOGIN;
}
public byte[] Guid
{
get
{
return GetBytes(16, 2);
}
}
public override Packet<LobbyPacketOpcode> New()
{
return new CM_REQUEST_LOGIN();
}
public override void OnProcess(Session<LobbyPacketOpcode> client)
{
((LobbySession)client).OnRequestLogin(this);
}
}Code: C++
Свернуть ↑Развернуть ↓
Свернуть ↑
public class CM_AUTH : Packet<LobbyPacketOpcode>
{
public CM_AUTH()
{
this.ID = LobbyPacketOpcode.CM_AUTH;
}
public Guid Token
{
get
{
return new Guid(GetBytes(16, 2));
}
}
public Guid AccountID
{
get
{
return new Guid(GetBytes(16, 18));
}
}
public override Packet<LobbyPacketOpcode> New()
{
return new CM_AUTH();
}
public override void OnProcess(Session<LobbyPacketOpcode> client)
{
((LobbySession)client).OnLoginAuth(this);
}
}Code: C++ public class SM_AUTH_RESULT : Packet<LobbyPacketOpcode>
{
public SM_AUTH_RESULT()
{
this.ID = LobbyPacketOpcode.SM_AUTH_RESULT;
Unknown1 = 2677811;
AES_KEY = Conversions.HexStr2Bytes("00000000000000000000000000000000");
}
public int Unknown1
{
set
{
PutInt(value, 2);
}
}
public byte[] AES_KEY
{
set
{
PutShort(16, 35);
PutBytes(value);
}
}
}Code: C++
Свернуть ↑Развернуть ↓
Свернуть ↑
public class CM_SERVER_LIST : Packet<LobbyPacketOpcode>
{
public CM_SERVER_LIST()
{
this.ID = LobbyPacketOpcode.CM_SERVER_LIST;
}
public override Packet<LobbyPacketOpcode> New()
{
return new CM_SERVER_LIST();
}
public override void OnProcess(Session<LobbyPacketOpcode> client)
{
((LobbySession)client).OnWorldListRequest(this);
}
}Code: C++ public class SM_SERVER_LIST : Packet<LobbyPacketOpcode>
{
public SM_SERVER_LIST()
{
this.ID = LobbyPacketOpcode.SM_SERVER_LIST;
}
public ICollection<World> Worlds
{
set
{
PutUShort((ushort)value.Count, 6);
foreach (World w in value)
{
PutUShort((ushort)w.ID);
PutUShort((ushort)w.ID);
PutUShort((ushort)w.Name.Length);
PutBytes(Encoding.Unicode.GetBytes(w.Name));
PutByte(1);//Unknown
PutByte(1);//Unknown
PutBytes(w.IPAsArray);
PutUShort(w.Port);
PutInt(0);//Unknown
PutByte(1);// 0 offline 1 online
PutByte(1);//Unknown
PutInt(1);//Unknown
PutByte(1);//Unknown
PutUShort((ushort)w.MaxPlayerCount);
PutUShort((ushort)w.PlayerCount);
PutInt(w.MaxPlayerCount);
}
PutInt((int)this.Length - 6, 2);
}
}
}Code: C++
Свернуть ↑Развернуть ↓
Свернуть ↑
public class SM_Unk1 : Packet<LobbyPacketOpcode>
{
public SM_Unk1()
{
this.ID = LobbyPacketOpcode.SM_Unk1;
Unknown1 = 0x0;
}
public int Unknown1
{
set
{
PutInt(value, 2);
}
}
}Code: C++ public class SM_Unk2 : Packet<LobbyPacketOpcode>
{
public SM_Unk2()
{
this.ID = LobbyPacketOpcode.SM_Unk2;
Unknown1 = 0x7;
Unknown2 = 0x0;
Unknown3 = 25601;
}
public short Unknown1
{
set
{
PutInt(value, 2);
}
}
public int Unknown2
{
set
{
PutInt(value, 9);
}
}
public int Unknown3
{
set
{
PutInt(value, 6);
}
}
}Code: C++ public class SM_Unk3 : Packet<LobbyPacketOpcode>
{
public SM_Unk3()
{
this.ID = LobbyPacketOpcode.SM_Unk3;
Unknown1 = 0x2;
Unknown2 = 0x0;
}
public short Unknown1
{
set
{
PutInt(value, 2);
}
}
public int Unknown2
{
set
{
PutInt(value, 4);
}
}
}Code: C++
Свернуть ↑Развернуть ↓
Свернуть ↑Развернуть ↓
Свернуть ↑
public enum LobbyPacketOpcode
{
CM_AUTH = 0x3,
SM_AUTH_RESULT,
CM_KEEP_ALIVE = 0x9,
CM_REQUEST_LOGIN = 0xD,
SM_REQUEST_LOGIN,
CM_SERVER_LIST = 0x18,
SM_SERVER_LIST,
CM_CHARACTER_LIST = 0x1B,
SM_CHARACTER_LIST,
CM_CHAR_CREATE = 0x24,
SM_CHAR_CREATE,
SM_CHAR_CREATE_FAILED,
CM_CHAR_DELETE,
SM_CHAR_DELETE,
SM_CHAR_DELETE_FINISH = 0x2A,
CM_CHAR_DELETE_CANCEL,
SM_CHAR_DELETE_CANCEL,
CM_Unk1 = 0x35,
SM_Unk1,
CM_Unk2 = 0x3E,
SM_Unk2,
CM_Unk3 = 0x44,
SM_Unk3,
}Code: C++
Свернуть ↑Развернуть ↓
Свернуть ↑
public partial class LobbySession : Session<LobbyPacketOpcode>
{
Guid accountID;
Account acc;
public void OnLoginAuth(CM_AUTH p)
{
accountID = p.AccountID;
Logger.ShowInfo(string.Format("Account:{0} is loging in", p.AccountID));
AccountSession.Instance.RequestAccountInfo(accountID.ToUInt(), this);
}
public void OnGotAccountInfo(Base.Packets.AccountServer.AccountLoginResult result, Account acc)
{
Logger.ShowInfo(string.Format("Load Account info for {0}({1}):{2}", accountID, accountID.ToUInt(), result));
if (result == Base.Packets.AccountServer.AccountLoginResult.OK)
{
this.acc = acc;
SM_AUTH_RESULT p1 = new SM_AUTH_RESULT();
this.Network.SendPacket(p1);
}
}
public void OnWorldListRequest(CM_SERVER_LIST p)
{
SM_SERVER_LIST p1 = new SM_SERVER_LIST();
p1.Worlds = WorldManager.Instance.Worlds.Values;
this.Network.SendPacket(p1);
}
}Code: C++ Думаю вы в этом не нуждаетесь, так как напишите нечто свое...
Свернуть ↑Развернуть ↓
На этом лобби сервер заканчивается.
Свернуть ↑Развернуть ↓
Человеческая просьба. Если вы не ставите плюсики или "спасибо", то хотя бы не пишите гадости про код. Не нравится? Не комментируйте, пройдите мимо, закройте эту закладку, а лучше забудьте.
п.с. чуть позже выложу сниффы пакетов лобби сервера, уже раскодированные под последнюю версию клиента. Сможете сами их ковырять.
Добавлено через 1 час 33 минуты
Далее выкладываю свежий снифф лобби сервера:
Свернуть ↑
Sender:Client
Time Captured: [2014.03.20 19:07:22]
Opcode:0x0003
Name:CM_AUTH
Length:34
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
03 00 FC 10 85 0F CA 77 08 42 99 44 31 6E B2 8F
33 9B E9 5C B0 A6 A9 34 11 E1 B0 16 E6 1F 13 5E
99 2F
Sender:Server
Time Captured: [2014.03.20 19:07:22]
Opcode:0x0004
Name:SM_AUTH_RESULT
Length:53
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
04 00 99 FC 12 00 00 00 00 00 00 68 26 F3 7F BC
B6 EE 45 82 40 27 3D 94 0B 2B BA DE 7A EE 76 44
2F 00 00 10 00 FE 56 96 2F C5 90 7E F7 33 3A E7
C6 E2 13 E2 7E
Sender:Client
Time Captured: [2014.03.20 19:07:52]
Opcode:0x0009
Name:CM_KEEP_ALIVE
Length:2
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
09 00
Sender:Client
Time Captured: [2014.03.20 19:07:22]
Opcode:0x0018
Name:CM_SERVER_LIST
Length:2
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
18 00
Sender:Client
Time Captured: [2014.03.20 19:07:23]
Opcode:0x001B
Name:CM_CHARACTER_LIST
Length:2
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
1B 00
Sender:Server
Time Captured: [2014.03.20 19:07:24]
Opcode:0x001C
Name:SM_CHARACTER_LIST
Data Length:554
Character Count:2
Character GUID:FCF17A05B6B611E1A49DE41F136C9588
World ID:5
Name:보확찢
Appearence1:6363634E63737364777777636464776464646464646464
Race:Jin
Gender:Male
Class:BladeMaster
Appearence2:03000209010C18030E01020102020103070601012B0000000043003E34000E2605B0ECF10AC9E7F600F1000FDDBF0000F1140A00000F05D3141EF628C4BADD0000000005000000000000000000000000000000000000000000000000
Name Null Terminated:보확찢
Unknown 0x05:0
Map ID:1101
X:0
Y:0
Z:0
Level:1
Unknown 0x0B:0
HP:229
Unknown 0x0D:0
Gold:0
Weapon ID:0
Unknown 0x10:0
Costume ID:0
Unknown 0x12:0
Eye Accessory ID:0
Hat ID:0
Costume Accessory ID:0
Last Login: 1970.01.01 02:00:00
Unknown Bytes:0000000002D0000000
Character GUID:B21E098CB05111E3A20BE41F136C9588
World ID:15
Name:lunka
Appearence1:6363634E63737364777777636464776464646464646464
Race:Lyn
Gender:Female
Class:ForceMaster
Appearence2:01020A06010C05031002180302010202010102003900000000000E0000000E05050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Name Null Terminated:lunka
Unknown 0x05:0
Map ID:1101
X:0
Y:0
Z:0
Level:1
Unknown 0x0B:0
HP:206
Unknown 0x0D:0
Gold:0
Weapon ID:0
Unknown 0x10:0
Costume ID:0
Unknown 0x12:0
Eye Accessory ID:0
Hat ID:0
Costume Accessory ID:0
Last Login: 1970.01.01 02:00:00
Unknown Bytes:000000000100000000
Length:560
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
1C 00 2A 02 00 00 02 00 FC F1 7A 05 B6 B6 11 E1
A4 9D E4 1F 13 6C 95 88 05 00 03 00 F4 BC 55 D6
22 CC E7 00 E7 00 17 00 63 63 63 4E 63 73 73 64
77 77 77 63 64 64 77 64 64 64 64 64 64 64 64 00
00 04 01 00 01 02 00 01 03 00 5C 00 03 00 02 09
01 0C 18 03 0E 01 02 01 02 02 01 03 07 06 01 01
2B 00 00 00 00 43 00 3E 34 00 0E 26 05 B0 EC F1
0A C9 E7 F6 00 F1 00 0F DD BF 00 00 F1 14 0A 00
00 0F 05 D3 14 1E F6 28 C4 BA DD 00 00 00 00 05
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 04 00 F4 BC 55 D6 22 CC
00 00 05 00 00 00 06 00 4D 04 00 00 07 00 00 00
08 00 00 00 09 00 00 00 0A 00 01 0B 00 00 00 00
00 0C 00 E5 00 00 00 0D 00 00 00 0E 00 00 00 00
00 0F 00 00 00 00 00 10 00 00 00 00 00 11 00 00
00 00 00 12 00 00 00 00 00 13 00 00 00 00 00 14
00 00 00 00 00 15 00 00 00 00 00 00 00 00 00 00
00 00 00 02 D0 00 00 00 B2 1E 09 8C B0 51 11 E3
A2 0B E4 1F 13 6C 95 88 0F 00 05 00 6C 00 75 00
6E 00 6B 00 61 00 EB 00 EB 00 17 00 63 63 63 4E
63 73 73 64 77 77 77 63 64 64 77 64 64 64 64 64
64 64 64 00 00 03 01 00 02 02 00 03 03 00 5C 00
01 02 0A 06 01 0C 05 03 10 02 18 03 02 01 02 02
01 01 02 00 39 00 00 00 00 00 0E 00 00 00 0E 05
05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 04 00 6C 00
75 00 6E 00 6B 00 61 00 00 00 05 00 00 00 06 00
4D 04 00 00 07 00 00 00 08 00 00 00 09 00 00 00
0A 00 01 0B 00 00 00 00 00 0C 00 CE 00 00 00 0D
00 00 00 0E 00 00 00 00 00 0F 00 00 00 00 00 10
00 00 00 00 00 11 00 00 00 00 00 12 00 00 00 00
00 13 00 00 00 00 00 14 00 00 00 00 00 15 00 00
00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00
Sender:Client
Time Captured: [2014.03.20 19:07:46]
Opcode:0x0024
Name:CM_CHAR_CREATE
Length:175
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
24 00 B2 1E 09 8D B0 51 11 E3 A2 0B E4 1F 13 6C
95 88 1A 00 08 00 6C 00 75 00 6E 00 61 00 6C 00
75 00 6E 00 61 00 87 00 87 00 06 00 63 63 63 4E
63 73 00 00 03 01 00 02 02 00 03 03 00 5C 00 01
02 0A 06 01 0C 05 03 10 02 18 03 02 01 02 02 01
01 02 00 39 00 00 00 00 00 0E 00 00 00 0E 05 05
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 04 00 6C 00 75
00 6E 00 61 00 6C 00 75 00 6E 00 61 00 00 00
Sender:Server
Time Captured: [2014.03.20 19:07:52]
Opcode:0x0025
Name:SM_CHAR_CREATE
Length:298
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
25 00 B2 1E 09 8D B0 51 11 E3 A2 0B E4 1F 13 6C
95 88 1A 00 09 00 6C 00 75 00 6E 00 61 00 6C 00
75 00 6E 00 61 00 6C 00 F3 00 F3 00 17 00 63 63
63 4E 63 73 73 64 77 77 77 63 64 64 77 64 64 64
64 64 64 64 64 00 00 03 01 00 02 02 00 03 03 00
5C 00 01 02 0A 06 01 0C 05 03 10 02 18 03 02 01
02 02 01 01 02 00 39 00 00 00 00 00 0E 00 00 00
0E 05 05 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00
6C 00 75 00 6E 00 61 00 6C 00 75 00 6E 00 61 00
6C 00 00 00 05 00 00 00 06 00 4D 04 00 00 07 00
00 00 08 00 00 00 09 00 00 00 0A 00 01 0B 00 00
00 00 00 0C 00 CE 00 00 00 0D 00 00 00 0E 00 00
00 00 00 0F 00 00 00 00 00 10 00 00 00 00 00 11
00 00 00 00 00 12 00 00 00 00 00 13 00 00 00 00
00 14 00 00 00 00 00 15 00 00 00 00 00 00 00 00
00 00 00 00 00 00 F8 01 00 00
Sender:Server
Time Captured: [2014.03.20 19:07:46]
Opcode:0x0026
Name:SM_CHAR_CREATE_FAILED
Length:20
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
26 00 B2 1E 09 8D B0 51 11 E3 A2 0B E4 1F 13 6C
95 88 7A 00
Sender:Client
Time Captured: [2014.03.20 19:08:07]
Opcode:0x0027
Name:CM_CHAR_DELETE
0xE31151B08C091EB2
Length:18
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
27 00 B2 1E 09 8C B0 51 11 E3 A2 0B E4 1F 13 6C
95 88
Sender:Server
Time Captured: [2014.03.20 19:08:07]
Opcode:0x0028
Name:SM_CHAR_DELETE
Length:23
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
28 00 B2 1E 09 8C B0 51 11 E3 A2 0B E4 1F 13 6C
95 88 01 68 01 00 00
Sender:Client
Time Captured: [2014.03.20 19:08:13]
Opcode:0x002B
Name:CM_CHAR_DELETE_CANCEL
Length:18
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
2B 00 FC F1 7A 05 B6 B6 11 E1 A4 9D E4 1F 13 6C
95 88
Sender:Server
Time Captured: [2014.03.20 19:08:14]
Opcode:0x002C
Name:SM_CHAR_DELETE_CANCEL
Length:18
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
2C 00 FC F1 7A 05 B6 B6 11 E1 A4 9D E4 1F 13 6C
95 88
Sender:Client
Time Captured: [2014.03.20 19:07:23]
Opcode:0x0035
Name:CM_Unk1
Length:2
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
35 00
Sender:Server
Time Captured: [2014.03.20 19:07:23]
Opcode:0x0036
Name:SM_Unk1
Length:6
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
36 00 00 00 00 00
Sender:Client
Time Captured: [2014.03.20 19:07:23]
Opcode:0x003E
Name:CM_Unk2
Length:11
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
3E 00 01 00 00 00 00 00 00 00 00
Sender:Server
Time Captured: [2014.03.20 19:07:23]
Opcode:0x003F
Name:SM_Unk2
Length:13
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
3F 00 07 00 00 00 01 64 00 00 00 00 00
Sender:Client
Time Captured: [2014.03.20 19:07:24]
Opcode:0x0044
Name:CM_Unk3
Length:2
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
44 00
Sender:Server
Time Captured: [2014.03.20 19:07:24]
Opcode:0x0045
Name:SM_Unk3
Length:8
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
45 00 02 00 00 00 00 00
Sender:Client
Time Captured: [2014.03.20 19:07:23]
Opcode:0x0059
Name:89
Length:2
Data:
=================================================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
=================================================
59 00
Code: C++
Свернуть ↑Развернуть ↓
Первый байт означает опкод, второй байт является определяющим тип пакета. Таким образом грубо говоря, первые два байта можно использовать как опкод. Пакеты читаются очень легко, поэтому читающий да прочтет!
Последний раз редактировалось luna9966; 20.03.2014 в 20:27.
Причина: Добавлено сообщение
|