Exemple #1
0
        /// <summary>
        /// Structures the data into a JSON string, prints it to the console. This uses a StringBuilder sized to the largest packet recieved of each packet type.
        /// This uses less memory than the RAM-heavy method, but it uses more CPU time in exchange. This is probably the best option for low-spec systems.
        /// </summary>
        private void OutputPacketSpecific(IpcPacket ipcData)
        {
            // Fetch the StringBuilder capacity.
            NameSizePair ipcMessageSize;

            if (MessageSizes.Exists((nsp) => nsp.Key == ipcData.Type))
            {
                ipcMessageSize = MessageSizes.Find((nsp) => nsp.Key == ipcData.Type);
            }
            else
            {
                ipcMessageSize = new NameSizePair(ipcData.Type, Capacity);
                MessageSizes.Add(ipcMessageSize);
            }

            // This is a modification of the CPU-heavy logger.
            StringBuilder sb = OutputCPUHeavy(ipcData);

            // Update the size so that future StringBuilders don't need to repeatedly resize themselves.
            if (ipcData.Type != "unknown" && sb.Capacity > ipcMessageSize.Value)
            {
                MessageSizes.Remove(ipcMessageSize);
                ipcMessageSize = new NameSizePair(ipcData.Type, sb.Capacity);
                MessageSizes.Add(ipcMessageSize);
            }
        }
        /// <summary>
        /// Structures the data into a JSON string, and does some preliminary byte parsing.
        /// </summary>
        public void Parse(Packet meta)
        {
            if (meta.Data.Length == 0) // See #41, this shouldn't happen but it somehow has in that case, may as well add this
            {
                Trace.WriteLine("Received packet with no IPC header or body, skipping...");
                return;
            }

            // Checking endianness
            if (!BitConverter.IsLittleEndian)
            {
                meta.Data = meta.Data.Reverse().ToArray();
            }

            // Get packet size.
            meta.PacketSize = BitConverter.ToUInt32(meta.Data, (int)Offsets.PacketSize);

            // Actor ID obfuscation for some measure of privacy, discouraging stalking and the like.
            // Ideally this data could just be wiped out, but that would make IPC data useless for minimap features.
            var sourceActorID = (int)Offsets.SourceActor + 4 < meta.PacketSize ? BitConverter.GetBytes(BitConverter.ToUInt32(meta.Data, (int)Offsets.SourceActor) ^ Modulator) : new byte[4];
            var targetActorID = (int)Offsets.TargetActor + 4 < meta.PacketSize ? BitConverter.GetBytes(BitConverter.ToUInt32(meta.Data, (int)Offsets.TargetActor) ^ Modulator) : new byte[4];

            // Copy obfuscated data in
            for (var i = 0; i < 4; i++)
            {
                meta.Data[(int)Offsets.SourceActor + i] = sourceActorID[i];
                meta.Data[(int)Offsets.TargetActor + i] = targetActorID[i];
            }

            // Get IPC data, if applicable.
            meta.SegmentType = (int)Offsets.SegmentType + 2 < meta.PacketSize ? BitConverter.ToUInt16(meta.Data, (int)Offsets.SegmentType) : new ushort();
            var ipcData = new IpcPacket(meta);

            if (meta.SegmentType == 3) // IPC segment type
            {
                ProcessIPCData(ref ipcData);
            }

            ipcData.Type ??= "unknown"; // Check if the property name exists
            Util.JSify(ref ipcData.Type);

            switch (Mode)
            {
            case ParserMode.RAMHeavy:
                OutputRAMHeavy(ipcData);
                break;

            case ParserMode.CPUHeavy:
                OutputCPUHeavy(ipcData);
                break;

            case ParserMode.PacketSpecific:
                OutputPacketSpecific(ipcData);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// Structures the data into a JSON string, prints it to the console. This uses a StringBuilder that sizes dynamically to each packet.
        /// This uses quite a bit of runtime resizing the StringBuilder repeatedly, and will cause a noticable slowdown in-game if many packets are being parsed at once.
        /// </summary>
        private StringBuilder OutputCPUHeavy(IpcPacket ipcData, int?capacity = null)
        {
            // The JSON consists of potentially useful header information and the IPC data if it exists.
            // Heavy data processing is done on the Node side, since it's easier to test packet structures like that.
            var JSON = new StringBuilder(capacity ?? Capacity);

            JSON.Append("{\"type\":\"").Append(ipcData.Type).Append("\",")
            .Append("\"opcode\":").Append(ipcData.Opcode).Append(",")
            .Append("\"region\":\"").Append(Region).Append("\",")
            .Append("\"connection\":\"").Append(ipcData.Metadata.ConnectionRoute).Append("\",")
            .Append("\"operation\":\"").Append(ipcData.Metadata.ConnectionType).Append("\",")
            .Append("\"epoch\":").Append(ipcData.Metadata.Epoch).Append(",")
            .Append("\"packetSize\":").Append(ipcData.Metadata.PacketSize).Append(",")
            .Append("\"segmentType\":").Append(ipcData.Metadata.SegmentType).Append(",");
            if (ipcData.Metadata.SegmentType == 3)
            {
                // IPC header info
                JSON.Append("\"sourceActorSessionID\":").Append(BitConverter.ToUInt32(ipcData.Metadata.Data, (int)Offsets.SourceActor)).Append(",")
                .Append("\"targetActorSessionID\":").Append(BitConverter.ToUInt32(ipcData.Metadata.Data, (int)Offsets.TargetActor)).Append(",")
                .Append("\"serverID\":").Append(ipcData.ServerId).Append(",")
                .Append("\"timestamp\":").Append(ipcData.Timestamp).Append(",");

                // Trim useless information
                ipcData.Metadata.Data = ipcData.Metadata.Data.Skip((int)Offsets.IpcData).ToArray();

                // If the IPC type isn't unknown we might have category data sitting around
                if (ipcData.ActorControlCategory != null)
                {
                    JSON.Append("\"superType\":\"actorControl\",")
                    .Append("\"subType\":\"").Append(ipcData.ActorControlCategory).Append("\",");
                }
                else if (ipcData.ClientTriggerCategory != null)
                {
                    JSON.Append("\"superType\":\"clientTrigger\",")
                    .Append("\"subType\":\"").Append(ipcData.ClientTriggerCategory).Append("\",");
                }
            }
            JSON.Append("\"data\":[").Append(string.Join(",", ipcData.Metadata.Data)).Append("]}");

            var message = new StringContent(JSON.ToString(), Encoding.UTF8, "application/json");

#if DEBUG
            Console.WriteLine(JSON.ToString());
#else
            try
            {
                http.PostAsync("http://localhost:" + Port, message);
            }
            catch (HttpRequestException e)
            {
                Console.Error.WriteLine(e.Message);
            }
#endif

            return(JSON);
        }
Exemple #4
0
        /// <summary>
        /// Structures the data into a JSON string, prints it to the console. This uses a StringBuilder sized to the largest packet recieved.
        /// This can use quite a bit of RAM and can crash low-memory systems if many packets are being parsed at once. Modern computers can run this happily.
        /// </summary>
        private void OutputRAMHeavy(IpcPacket ipcData)
        {
            // This is just a slight modification of the CPU-heavy logger.
            StringBuilder sb = OutputCPUHeavy(ipcData);

            // Update the size so that future StringBuilders don't need to repeatedly resize themselves.
            // This is likely to be the main cause of memory usage increases.
            if (sb.Capacity > Capacity)
            {
                Capacity = sb.Capacity;
            }
        }
Exemple #5
0
        /// <summary>
        /// Structures the data into a JSON string, and does some preliminary byte parsing.
        /// </summary>
        public void Parse(Packet meta)
        {
            // Checking endianness
            if (!BitConverter.IsLittleEndian)
            {
                meta.Data = meta.Data.Reverse().ToArray();
            }

            // Get packet size.
            meta.PacketSize = BitConverter.ToUInt32(meta.Data, (int)Offsets.PacketSize);

            // Actor ID obfuscation for some measure of privacy, discouraging stalking and the like.
            // Ideally this data could just be wiped out, but that would make IPC data useless for minimap features.
            var sourceActorID = (int)Offsets.SourceActor + 4 < meta.PacketSize ? BitConverter.GetBytes(BitConverter.ToUInt32(meta.Data, (int)Offsets.SourceActor) ^ Modulator) : new byte[4];
            var targetActorID = (int)Offsets.TargetActor + 4 < meta.PacketSize ? BitConverter.GetBytes(BitConverter.ToUInt32(meta.Data, (int)Offsets.TargetActor) ^ Modulator) : new byte[4];

            // Copy obfuscated data in
            for (var i = 0; i < 4; i++)
            {
                meta.Data[(int)Offsets.SourceActor + i] = sourceActorID[i];
                meta.Data[(int)Offsets.TargetActor + i] = targetActorID[i];
            }

            // Get IPC data, if applicable.
            meta.SegmentType = (int)Offsets.SegmentType + 2 < meta.PacketSize ? BitConverter.ToUInt16(meta.Data, (int)Offsets.SegmentType) : new ushort();
            var ipcData = new IpcPacket(meta);

            if (meta.SegmentType == 3) // IPC segment type
            {
                ProcessIPCData(ref ipcData);
            }

            ipcData.Type = ipcData.Type ?? "unknown"; // Check if the property name exists
            Util.JSify(ref ipcData.Type);

            switch (Mode)
            {
            case ParserMode.RAMHeavy:
                OutputRAMHeavy(ipcData);
                break;

            case ParserMode.CPUHeavy:
                OutputCPUHeavy(ipcData);
                break;

            case ParserMode.PacketSpecific:
                OutputPacketSpecific(ipcData);
                break;
            }
        }
Exemple #6
0
 /// <summary>
 /// Switches the parser region if it detects an out-of-range world.
 /// </summary>
 private void ValidateRegion(IpcPacket ipcData)
 {
     // Check world ID for region validation
     if (ipcData.Type == "InitZone")
     {
         ushort worldId = BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.IpcData);
         if (Region != Region.Global && worldId >= 23 && worldId <= 99)
         {
             Region = Region.Global;
         }
         else if (Region != Region.KR && worldId >= 2050 && worldId <= 2583)
         {
             Region = Region.KR;
         }
         // TODO China
     }
 }
Exemple #7
0
        /// <summary>
        /// Structures the data into a JSON string, prints it to the console. This uses a StringBuilder that sizes dynamically to each packet.
        /// This uses quite a bit of runtime resizing the StringBuilder repeatedly, and will cause a noticable slowdown in-game if many packets are being parsed at once.
        /// </summary>
        private StringBuilder OutputCPUHeavy(IpcPacket ipcData, int?capacity = null)
        {
            // The JSON consists of potentially useful header information and the IPC data if it exists.
            // Heavy data processing is done on the Node side, since it's easier to test packet structures like that.
            StringBuilder JSON = new StringBuilder(capacity ?? Capacity);

            JSON.Append("{ \"type\": \"").Append(ipcData.Type).Append("\",\n");
            JSON.Append("  \"opcode\": ").Append(ipcData.Opcode).Append(",\n");
            JSON.Append("  \"region\": \"").Append(Region).Append("\",\n");
            JSON.Append("  \"connection\": \"").Append(ipcData.Metadata.ConnectionRoute).Append("\",\n");
            JSON.Append("  \"operation\": \"").Append(ipcData.Metadata.ConnectionType).Append("\",\n");
            JSON.Append("  \"epoch\": ").Append(ipcData.Metadata.Epoch).Append(",\n");
            JSON.Append("  \"packetSize\": ").Append(ipcData.Metadata.PacketSize).Append(",\n");
            JSON.Append("  \"segmentType\": ").Append(ipcData.Metadata.SegmentType).Append(",\n");
            if (ipcData.Metadata.SegmentType == 3)
            {
                // IPC header info
                JSON.Append("  \"sourceActorSessionID\": ").Append(BitConverter.ToUInt32(ipcData.Metadata.Data, (int)Offsets.SourceActor)).Append(",\n");
                JSON.Append("  \"targetActorSessionID\": ").Append(BitConverter.ToUInt32(ipcData.Metadata.Data, (int)Offsets.TargetActor)).Append(",\n");
                JSON.Append("  \"serverID\": ").Append(ipcData.ServerId).Append(",\n");
                JSON.Append("  \"timestamp\": ").Append(ipcData.Timestamp).Append(",\n");

                // Trim useless information
                ipcData.Metadata.Data = ipcData.Metadata.Data.Skip((int)Offsets.IpcData).ToArray();

                // If the IPC type isn't unknown we might have category data sitting around
                if (ipcData.ActorControlCategory != null)
                {
                    JSON.Append("  \"superType\": \"actorControl\",\n");
                    JSON.Append("  \"subType\": \"").Append(ipcData.ActorControlCategory).Append("\",\n");
                }
                else if (ipcData.ClientTriggerCategory != null)
                {
                    JSON.Append("  \"superType\": \"clientTrigger\",\n");
                    JSON.Append("  \"subType\": \"").Append(ipcData.ClientTriggerCategory).Append("\",\n");
                }
            }
            JSON.Append("  \"data\": [").Append(string.Join(",", ipcData.Metadata.Data)).Append("] }\n");

            Console.Out.Write(JSON.ToString());

            return(JSON);
        }
        /// <summary>
        /// Converts opcodes into readable strings.
        /// </summary>
        private void ProcessIPCData(ref IpcPacket ipcData)
        {
            // IPC opcode
            var ipcOpcode = (int)Offsets.IpcType + 2 < ipcData.Metadata.PacketSize ? BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.IpcType) : new ushort();

            ipcData.Opcode = ipcOpcode;
            if (ipcData.Metadata.ConnectionType == "receive")
            {
                ipcData.Type = ActiveOpcodeList.Lists.ServerZoneIpcType.FirstOrDefault(oi => oi.Opcode == ipcOpcode)?.Name;

                // ActorControl categories
                if (ipcData.Type == "ActorControl" || ipcData.Type == "ActorControlSelf" || ipcData.Type == "ActorControlTarget")
                {
                    var actorControlOpcode = BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.IpcData);
                    ipcData.ActorControlCategory = Enum.GetName(typeof(ActorControlType), actorControlOpcode) ?? "unknown";
                    // Camelcase it for JavaScript style
                    Util.JSify(ref ipcData.ActorControlCategory);
                }
            }
            else
            {
                ipcData.Type = ActiveOpcodeList.Lists.ClientZoneIpcType.FirstOrDefault(oi => oi.Opcode == ipcOpcode)?.Name;

                // ClientTrigger categories
                if (ipcData.Type == "ClientTrigger")
                {
                    var clientTriggerOpcode = BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.IpcData);
                    ipcData.ClientTriggerCategory = Enum.GetName(typeof(ClientTriggerType), clientTriggerOpcode) ?? "unknown";
                    Util.JSify(ref ipcData.ClientTriggerCategory);
                }
            }

            // Server ID and timestamp
            ipcData.ServerId  = (int)Offsets.ServerId + 2 < ipcData.Metadata.PacketSize ? BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.ServerId) : new ushort();
            ipcData.Timestamp = (int)Offsets.Timestamp + 4 < ipcData.Metadata.PacketSize ? BitConverter.ToUInt32(ipcData.Metadata.Data, (int)Offsets.Timestamp) : new uint();

            // ValidateRegion(ipcData);
        }
Exemple #9
0
        /// <summary>
        /// Converts opcodes into readable strings.
        /// </summary>
        private void ProcessIPCData(ref IpcPacket ipcData)
        {
            // IPC opcode
            ushort ipcOpcode = (int)Offsets.IpcType + 2 < ipcData.Metadata.PacketSize ? BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.IpcType) : new ushort();

            ipcData.Opcode = ipcOpcode;
            if (ipcData.Metadata.ConnectionType == "receive")
            {
                // Inbound packet
                if (Region == Region.Global)
                {
                    ipcData.Type = Enum.GetName(typeof(ServerZoneIpcType), ipcOpcode);
                    if (ipcData.Type == null)
                    {
                        ipcData.Type = Enum.GetName(typeof(ServerChatIpcType), ipcOpcode);
                    }
                }
                else if (Region == Region.KR)
                {
                    ipcData.Type = Enum.GetName(typeof(ServerZoneIpcTypeKR), ipcOpcode);
                    if (ipcData.Type == null)
                    {
                        ipcData.Type = Enum.GetName(typeof(ServerChatIpcTypeKR), ipcOpcode);
                    }
                }
                else if (Region == Region.CN)
                {
                    ipcData.Type = Enum.GetName(typeof(ServerZoneIpcTypeCN), ipcOpcode);
                    if (ipcData.Type == null)
                    {
                        ipcData.Type = Enum.GetName(typeof(ServerChatIpcTypeCN), ipcOpcode);
                    }
                }
                else
                {
                    throw new NoRegionException("No region set!");
                }

                // ActorControl categories
                if (ipcData.Type == "ActorControl" || ipcData.Type == "ActorControlSelf" || ipcData.Type == "ActorControlTarget")
                {
                    ushort actorControlOpcode = BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.IpcData);
                    ipcData.ActorControlCategory = Enum.GetName(typeof(ActorControlType), actorControlOpcode) ?? "unknown";
                    // Camelcase it for JavaScript style
                    Util.JSify(ref ipcData.ActorControlCategory);
                }
            }
            else
            {
                // Outbound packet
                if (Region == Region.Global)
                {
                    ipcData.Type = Enum.GetName(typeof(ClientZoneIpcType), ipcOpcode);
                    if (ipcData.Type == null)
                    {
                        ipcData.Type = Enum.GetName(typeof(ClientChatIpcType), ipcOpcode);
                    }
                }
                else if (Region == Region.KR)
                {
                    ipcData.Type = Enum.GetName(typeof(ClientZoneIpcTypeKR), ipcOpcode);
                    if (ipcData.Type == null)
                    {
                        ipcData.Type = Enum.GetName(typeof(ClientChatIpcTypeKR), ipcOpcode);
                    }
                }
                else if (Region == Region.CN)
                {
                    ipcData.Type = Enum.GetName(typeof(ClientZoneIpcTypeCN), ipcOpcode);
                    if (ipcData.Type == null)
                    {
                        ipcData.Type = Enum.GetName(typeof(ClientChatIpcTypeCN), ipcOpcode);
                    }
                }
                else
                {
                    throw new NoRegionException("No region set!");
                }

                // ClientTrigger categories
                if (ipcData.Type == "ClientTrigger")
                {
                    ushort clientTriggerOpcode = BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.IpcData);
                    ipcData.ClientTriggerCategory = Enum.GetName(typeof(ClientTriggerType), clientTriggerOpcode) ?? "unknown";
                    Util.JSify(ref ipcData.ClientTriggerCategory);
                }
            }

            // Server ID and timestamp
            ipcData.ServerId  = (int)Offsets.ServerId + 2 < ipcData.Metadata.PacketSize ? BitConverter.ToUInt16(ipcData.Metadata.Data, (int)Offsets.ServerId) : new ushort();
            ipcData.Timestamp = (int)Offsets.Timestamp + 4 < ipcData.Metadata.PacketSize ? BitConverter.ToUInt32(ipcData.Metadata.Data, (int)Offsets.Timestamp) : new uint();

            // ValidateRegion(ipcData);
        }