A3 returns help

Socius Decennalis
Decennium
Joined
Nov 16, 2012
Messages
101
Reaction score
21
It would be glad if some one can provide ACL file structure information about a3 returns.
The form in which bytes are stored etc etc.
 
acl - A3 returns help - RaGEZONE Forums

attached image is one of a slot.
packet is composed of a HEADER + 5 slots DATA.

but, in Returns(572), all packets has changed.
but, in Returns(578), all packets has changed.
 
Last edited:
View attachment 157112

attached image is one of a slot.
packet is composed of a HEADER + 5 slots DATA.

but, in Returns(572), all packets has changed.

Thank you prologs for the reply.
I would like to know more about headers in which you have marked with Ctrl, Cmd and Protocol. What are this in header?
And does this 578 packet structure (shown in image) works with returns client ?
 
I tried login using cracked client of a3 returns provided by prologos,
But don't know where the problem is, client crashes on login and on LS it shows user disconnected.
 
I tried login using cracked client of a3 returns provided by prologos,
But don't know where the problem is, client crashes on login and on LS it shows user disconnected.
Does the client DC after getting character list packet or before?
 
Does the client DC after getting character list packet or before?

Before character packet,
As I entered username and password pressed enter and client crashes,
login packet is received by login agent and login server, but disconnects as client crashes
 
Before character packet,
As I entered username and password pressed enter and client crashes,
login packet is received by login agent and login server, but disconnects as client crashes
Then there might be slight difference in the packet structure format hence while trying to parse it the client is crashing (Maybe array out of bounds?)
 
Then there might be slight difference in the packet structure format hence while trying to parse it the client is crashing (Maybe array out of bounds?)

May be possible. Will try it out differently modifying login packets and will post results.
 
1. Login packet has been changed. It must be treated with LA.

2. encrypt/decrypt function is substantially the same as 562.
578, to encrypt/decrypt the protocol part of the header in a new way.

*Examples of encrypt/decrypt function in C#
Code:
class Config
    {
        public static int m_ConstKey1 = 0x241AE7;
        public static int m_ConstKey2 = 0x15DCB2;
        public static int m_DynamicKey = 0x4C478BD;
        public const int p_Type562 = 0x0C;
        public const int p_Type578 = 0x0A;
        public static int p_DynamicKey1 = 0x02;
        public static int p_DynamicKey2 = 0x01;
        public static uint p_ConstKey_En = 0xA7F0753B;
        public static uint p_ConstKey_De = 0xAAF29BF3;
    }

Code:
class Crypt
    {
        public static byte[] Decrypt(byte[] packet, int Type = Config.p_Type578)
        {
            //[0]-[11]: Packet Header
            for (int i = Type; i + 4 <= packet.Length; i += 4)
            {
                if (i == Config.p_Type578)
                {
                    uint wProtocol = (BitConverter.ToUInt32(packet, i) * Config.p_ConstKey_De) >> 16;
                    var wProtocolByte = BitConverter.GetBytes(wProtocol);
                    Buffer.BlockCopy(wProtocolByte, 0, packet, 10, 4);
                    continue;
                }
                int DynamicKey = Config.m_DynamicKey;
                for (int j = i; j < i + 4; j++)
                {
                    byte pSrc = packet[j];
                    packet[j] = (byte)(packet[j] ^ (DynamicKey >> 8));
                    DynamicKey = (pSrc + DynamicKey) * Config.m_ConstKey1 + Config.m_ConstKey2;
                }
            }
            return packet;
        }

        public static byte[] Encrypt(byte[] packet, int Type = Config.p_Type578)
        {
            //[0]-[11]: Packet Header
            for (int i = Type; i + 4 <= packet.Length; i += 4)
            {
                if (i == Config.p_Type578)
                {
                    uint wProtocol = (uint)((BitConverter.ToUInt16(packet, i) << 16) + (Config.p_DynamicKey1 << 8) + Config.p_DynamicKey2) * Config.p_ConstKey_En;
                    var wProtocolByte = BitConverter.GetBytes(wProtocol);
                    Buffer.BlockCopy(wProtocolByte, 0, packet, 10, 4);
                    Config.p_DynamicKey2 = (byte)Config.p_DynamicKey1 + Config.p_DynamicKey2;
                    Config.p_DynamicKey1 = (byte)Config.p_DynamicKey1 + 0xB3;
                    continue;
                }
                int DynamicKey = Config.m_DynamicKey;
                for (int j = i; j < i + 4; j++)
                {
                    packet[j] = (byte)(packet[j] ^ (DynamicKey >> 8));
                    DynamicKey = (packet[j] + DynamicKey) * Config.m_ConstKey1 + Config.m_ConstKey2;
                }
            }
            return packet;
        }
    }
Precisely, using the random number to encrypt the part of the protocol. However, to work well, just above code.
 
1. Login packet has been changed. It must be treated with LA.

2. encrypt/decrypt function is substantially the same as 562.
578, to encrypt/decrypt the protocol part of the header in a new way.

*Examples of encrypt/decrypt function in C#
Code:
class Config
    {
        public static int m_ConstKey1 = 0x241AE7;
        public static int m_ConstKey2 = 0x15DCB2;
        public static int m_DynamicKey = 0x4C478BD;
        public const int p_Type562 = 0x0C;
        public const int p_Type578 = 0x0A;
        public static int p_DynamicKey1 = 0x02;
        public static int p_DynamicKey2 = 0x01;
        public static uint p_ConstKey_En = 0xA7F0753B;
        public static uint p_ConstKey_De = 0xAAF29BF3;
    }

Code:
class Crypt
    {
        public static byte[] Decrypt(byte[] packet, int Type = Config.p_Type578)
        {
            //[0]-[11]: Packet Header
            for (int i = Type; i + 4 <= packet.Length; i += 4)
            {
                if (i == Config.p_Type578)
                {
                    uint wProtocol = (BitConverter.ToUInt32(packet, i) * Config.p_ConstKey_De) >> 16;
                    var wProtocolByte = BitConverter.GetBytes(wProtocol);
                    Buffer.BlockCopy(wProtocolByte, 0, packet, 10, 4);
                    continue;
                }
                int DynamicKey = Config.m_DynamicKey;
                for (int j = i; j < i + 4; j++)
                {
                    byte pSrc = packet[j];
                    packet[j] = (byte)(packet[j] ^ (DynamicKey >> 8));
                    DynamicKey = (pSrc + DynamicKey) * Config.m_ConstKey1 + Config.m_ConstKey2;
                }
            }
            return packet;
        }

        public static byte[] Encrypt(byte[] packet, int Type = Config.p_Type578)
        {
            //[0]-[11]: Packet Header
            for (int i = Type; i + 4 <= packet.Length; i += 4)
            {
                if (i == Config.p_Type578)
                {
                    uint wProtocol = (uint)((BitConverter.ToUInt16(packet, i) << 16) + (Config.p_DynamicKey1 << 8) + Config.p_DynamicKey2) * Config.p_ConstKey_En;
                    var wProtocolByte = BitConverter.GetBytes(wProtocol);
                    Buffer.BlockCopy(wProtocolByte, 0, packet, 10, 4);
                    Config.p_DynamicKey2 = (byte)Config.p_DynamicKey1 + Config.p_DynamicKey2;
                    Config.p_DynamicKey1 = (byte)Config.p_DynamicKey1 + 0xB3;
                    continue;
                }
                int DynamicKey = Config.m_DynamicKey;
                for (int j = i; j < i + 4; j++)
                {
                    packet[j] = (byte)(packet[j] ^ (DynamicKey >> 8));
                    DynamicKey = (packet[j] + DynamicKey) * Config.m_ConstKey1 + Config.m_ConstKey2;
                }
            }
            return packet;
        }
    }
Precisely, using the random number to encrypt the part of the protocol. However, to work well, just above code.
As usual prologos saving the day :thumbup:
 
1. Login packet has been changed. It must be treated with LA.

2. encrypt/decrypt function is substantially the same as 562.
578, to encrypt/decrypt the protocol part of the header in a new way.

*Examples of encrypt/decrypt function in C#
Code:
class Config
    {
        public static int m_ConstKey1 = 0x241AE7;
        public static int m_ConstKey2 = 0x15DCB2;
        public static int m_DynamicKey = 0x4C478BD;
        public const int p_Type562 = 0x0C;
        public const int p_Type578 = 0x0A;
        public static int p_DynamicKey1 = 0x02;
        public static int p_DynamicKey2 = 0x01;
        public static uint p_ConstKey_En = 0xA7F0753B;
        public static uint p_ConstKey_De = 0xAAF29BF3;
    }

Code:
class Crypt
    {
        public static byte[] Decrypt(byte[] packet, int Type = Config.p_Type578)
        {
            //[0]-[11]: Packet Header
            for (int i = Type; i + 4 <= packet.Length; i += 4)
            {
                if (i == Config.p_Type578)
                {
                    uint wProtocol = (BitConverter.ToUInt32(packet, i) * Config.p_ConstKey_De) >> 16;
                    var wProtocolByte = BitConverter.GetBytes(wProtocol);
                    Buffer.BlockCopy(wProtocolByte, 0, packet, 10, 4);
                    continue;
                }
                int DynamicKey = Config.m_DynamicKey;
                for (int j = i; j < i + 4; j++)
                {
                    byte pSrc = packet[j];
                    packet[j] = (byte)(packet[j] ^ (DynamicKey >> 8));
                    DynamicKey = (pSrc + DynamicKey) * Config.m_ConstKey1 + Config.m_ConstKey2;
                }
            }
            return packet;
        }

        public static byte[] Encrypt(byte[] packet, int Type = Config.p_Type578)
        {
            //[0]-[11]: Packet Header
            for (int i = Type; i + 4 <= packet.Length; i += 4)
            {
                if (i == Config.p_Type578)
                {
                    uint wProtocol = (uint)((BitConverter.ToUInt16(packet, i) << 16) + (Config.p_DynamicKey1 << 8) + Config.p_DynamicKey2) * Config.p_ConstKey_En;
                    var wProtocolByte = BitConverter.GetBytes(wProtocol);
                    Buffer.BlockCopy(wProtocolByte, 0, packet, 10, 4);
                    Config.p_DynamicKey2 = (byte)Config.p_DynamicKey1 + Config.p_DynamicKey2;
                    Config.p_DynamicKey1 = (byte)Config.p_DynamicKey1 + 0xB3;
                    continue;
                }
                int DynamicKey = Config.m_DynamicKey;
                for (int j = i; j < i + 4; j++)
                {
                    packet[j] = (byte)(packet[j] ^ (DynamicKey >> 8));
                    DynamicKey = (packet[j] + DynamicKey) * Config.m_ConstKey1 + Config.m_ConstKey2;
                }
            }
            return packet;
        }
    }
Precisely, using the random number to encrypt the part of the protocol. However, to work well, just above code.

Great prologos , thanks for the code snippet.
As you mentioned 1st point about login packets are changed.
I observed login packet is of 64 bytes which was 56 bytes in case of v562.
So it would be glad if you can provide with login packet structure and its response to be send from server.
 
Great prologos , thanks for the code snippet.
As you mentioned 1st point about login packets are changed.
I observed login packet is of 64 bytes which was 56 bytes in case of v562.
So it would be glad if you can provide with login packet structure and its response to be send from server.

perhaps... Try the following code to the Inferno-Login-Agent-562

*change on line 130 of Packet.cs
case 52:
desiredPacket = new byte[] { 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0 };
if (desiredPacket.SequenceEqual(packetGot))
{
var temp = CreateReverseHexPacket(cindex);
buffer[4] = temp[0];
buffer[5] = temp[1];
returnPacket = buffer;
}
break;


case 64:
desiredPacket = new byte[] { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0 };
if (desiredPacket.SequenceEqual(packetGot))
{
var temp = CreateReverseHexPacket(cindex);
buffer[4] = temp[0];
buffer[5] = temp[1];
returnPacket = buffer;
}
break;


*add function to Packet.cs
public static byte[] CreateServerList(byte[] buffer)
{
var packetLen = BitConverter.ToInt32(new byte[] { buffer[0], buffer[1], buffer[2], buffer[3] }, 0);
var newPacket = new byte[packetLen + 21];
byte[] byteArray = BitConverter.GetBytes(packetLen + 21);
Buffer.BlockCopy(byteArray, 0, newPacket, 0, 4);
Buffer.BlockCopy(buffer, 4, newPacket, 4, 6);
Buffer.BlockCopy(buffer, 10, newPacket, 31, packetLen - 10);
return newPacket;
}


*change on line 271 of LoginAgent.cs
else if (Encoding.ASCII.GetString(bytes).Substring(30, 6) == "ONLINE")
{
// Prepend welcome message to the server name data
bytes = Packet.CombineByteArray(Packet.CreateWelcomeMessage(cindex), Packet.TrimPacket(bytes));
}


else if (Encoding.ASCII.GetString(bytes).Substring(30, 6) == "ONLINE" || Encoding.ASCII.GetString(bytes).Substring(30, 7) == "OFFLINE")
{
// Prepend welcome message to the server name data
bytes = Packet.CreateServerList(bytes);
}



Perhaps the code is not perfect. However, the Test is possible.
 
perhaps... Try the following code to the Inferno-Login-Agent-562

*change on line 130 of Packet.cs
case 52:
desiredPacket = new byte[] { 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0 };
if (desiredPacket.SequenceEqual(packetGot))
{
var temp = CreateReverseHexPacket(cindex);
buffer[4] = temp[0];
buffer[5] = temp[1];
returnPacket = buffer;
}
break;


case 64:
desiredPacket = new byte[] { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0 };
if (desiredPacket.SequenceEqual(packetGot))
{
var temp = CreateReverseHexPacket(cindex);
buffer[4] = temp[0];
buffer[5] = temp[1];
returnPacket = buffer;
}
break;


*add function to Packet.cs
public static byte[] CreateServerList(byte[] buffer)
{
var packetLen = BitConverter.ToInt32(new byte[] { buffer[0], buffer[1], buffer[2], buffer[3] }, 0);
var newPacket = new byte[packetLen + 21];
byte[] byteArray = BitConverter.GetBytes(packetLen + 21);
Buffer.BlockCopy(byteArray, 0, newPacket, 0, 4);
Buffer.BlockCopy(buffer, 4, newPacket, 4, 6);
Buffer.BlockCopy(buffer, 10, newPacket, 31, packetLen - 10);
return newPacket;
}


*change on line 271 of LoginAgent.cs
else if (Encoding.ASCII.GetString(bytes).Substring(30, 6) == "ONLINE")
{
// Prepend welcome message to the server name data
bytes = Packet.CombineByteArray(Packet.CreateWelcomeMessage(cindex), Packet.TrimPacket(bytes));
}


else if (Encoding.ASCII.GetString(bytes).Substring(30, 6) == "ONLINE" || Encoding.ASCII.GetString(bytes).Substring(30, 7) == "OFFLINE")
{
// Prepend welcome message to the server name data
bytes = Packet.CreateServerList(bytes);
}



Perhaps the code is not perfect. However, the Test is possible.
prologos Great work, Thanks, I was able to login, now trying to sort out character packets
 
Back