[RESOURCE] Packet Structure Information

◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,165
Reaction score
912
Point Blanks / Project Blackout / Piercing blow uses binary packets with a header of 4 bytes.
This header contains the information of the packet data length and packet opcode (id). Both of these values are ushorts, which are both 2 bytes each. The rest of the packet is the content, the length of the content is based on the length that set inside the header. So the packet content's length is equal to the ushort value of the first 2 bytes.



Taiga - [RESOURCE] Packet Structure Information - RaGEZONE Forums


Server packets are not encrypted at all, they are send directly without encryption. The client packets are 'encrypted' with a bit shift function. The bits of the packet are moved by x bits based on the offset that was sent in the first packet. The packet gets shifted with maximum 8 bits. I'm still not 100% sure of the offset so I use a static 'key' offset to calculate the bit shifting size.

The you can calculate the **** size by doing the following math:
Code:
shiftSize = ((offset) % 7) + 1


There is always a bit shift of at least 1 bit. 8 bits at max. The last (or overflowing) bits are moved to the beginning.
 
To recieve shiftsize the client uses session id that is given by server first packet.

For Piercing Blow or others which use this engine:


Code:
class PROTOCOL_BASE_CONNECT_ACK : Packet // Opcode 514 (0x202)
{
    public override void WriteImpl()
    {
        WriteH(0); // ?
        WriteD(Session.Id); // <-- This
        WriteH(Session.Salt);
        
        // ...
    }
}

For old Point Blank or Project Blackout:


Code:
class PROTOCOL_BASE_SERVERLIST_ACK : Packet // Opcode 2049 (0x801)
{
    public override void WriteImpl()
    {
        WriteD(Session.Id); // <-- This
        WriteIP(Session.RemoteIPAddress);
        WriteH(Session.RemoteUdpPort);
        WriteH(Session.Salt);
        
        // ...
    }
}

I assign session id like this:

Code:
public class ClientManager : SingletonHelper<ClientManager>
{
    /// <summary>
    /// Session holder
    /// </summary>
    static readonly Dictionary<int, NetworkSession> _sessions
        = new Dictionary<int, NetworkSession>();


    /// <summary>
    /// Session id
    /// </summary>
    static int _sessionId = 0;


    /// <summary>
    /// Accept new client
    /// </summary>
    /// <param name="arg"></param>
    public void Accept(IAsyncResult arg)
    {
        TcpListener listener = arg.AsyncState as TcpListener;
        TcpClient client = listener.EndAcceptTcpClient(arg);


        Connected(client);


        listener.BeginAcceptTcpClient(Accept, listener);
    }


    /// <summary>
    /// Connected client
    /// </summary>
    /// <param name="client"></param>
    static void Connected(TcpClient client)
    {
        Interlocked.Increment(ref _sessionId);


        NetworkSession session = new NetworkSession() {
            Id = _sessionId
        };


        session.Accept(client);
        session.OnDisconnected += Disconnected;


        _sessions.Add(session.Id, session);


        _log.Info("New client session #{0} is connected.", session.Id);
    }


    /// <summary>
    /// Disconnected client
    /// </summary>
    /// <param name="session"></param>
    static void Disconnected(NetworkSession session)
    {
        session.OnDisconnected -= Disconnected;


        _sessions.Remove(session.Id);


        _log.Info("Client session #{0} disconnected from server.", session.Id);


        session = null;
    }
}
 
In client it is named as RandSeed (rnd short number), and is used to make the same packet after encrypt to look differ.


Code:
S2MOPacketBase::SetPacketRandSeed(randSeed);
 
In client it is named as RandSeed (rnd short number), and is used to make the same packet after encrypt to look differ.


Code:
S2MOPacketBase::SetPacketRandSeed(randSeed);

thats mean randseed is useless since bit rotate method solve the issue from encrypt, thats correct ?
 
Point Blanks / Project Blackout / Piercing blow uses binary packets with a header of 4 bytes.
This header contains the information of the packet data length and packet opcode (id). Both of these values are ushorts, which are both 2 bytes each. The rest of the packet is the content, the length of the content is based on the length that set inside the header. So the packet content's length is equal to the ushort value of the first 2 bytes.



Taiga - [RESOURCE] Packet Structure Information - RaGEZONE Forums


Server packets are not encrypted at all, they are send directly without encryption. The client packets are 'encrypted' with a bit shift function. The bits of the packet are moved by x bits based on the offset that was sent in the first packet. The packet gets shifted with maximum 8 bits. I'm still not 100% sure of the offset so I use a static 'key' offset to calculate the bit shifting size.

The you can calculate the **** size by doing the following math:
Code:
shiftSize = ((offset) % 7) + 1


There is always a bit shift of at least 1 bit. 8 bits at max. The last (or overflowing) bits are moved to the beginning.

Anyone know how packet are encrypted on the new client? (v3.41)
I'm using this way to decrypt the packets, but this isn't working all the times. Maybe there is a different key sended on the first packet?

Code:
        static int Key { get; set; }
        static int GetKey { get { return 29890; } }
        static int GetId { get { return 5404; } }
        static void SetShiftSize(int _key) { Key = _key; }
        static int GetShiftSize { get { return Key; } }

        internal static byte[] Decrypt(byte[] _packet)
        {
            int id = GetId, key = GetKey, shiftSize = GetShiftSize;
            if (shiftSize == 0 || shiftSize == -1)
            {
                shiftSize = ((id + GetKey) % 7) + 1;
                SetShiftSize(shiftSize);
            }
            byte[] bytes = UntangleBuffer(_packet, shiftSize);
            return bytes;
        }

        internal static byte[] UntangleBuffer(byte[] _buffer, int _shiftsize)
        {
            int size = _buffer.Length - 1;
            byte lastByte = _buffer[size];
            for (int ii = size; ii > 0; ii--)
            {
                _buffer[ii] = (byte)(_buffer[ii] / 2);
            }
            _buffer[0] = (byte)(_buffer[0] / 2);
            return _buffer;
        }
 
Last edited:
Back