/// <summary> /// Initializes a new instance of the <see cref="PacketAnalyzer"/> class. /// The configuration is automatically loaded from the configuration files. /// </summary> public PacketAnalyzer() { this.LoadAndWatchConfiguration(def => this.serverPacketDefinitions = def, ServerToClientPacketsFile); this.LoadAndWatchConfiguration(def => this.clientPacketDefinitions = def, ClientToServerPacketsFile); }
/// <summary> /// Initializes a new instance of the <see cref="PacketAnalyzer"/> class /// with the specified configurations. /// </summary> /// <param name="clientPacketDefinitions">The client packet definitions.</param> /// <param name="serverPacketDefinitions">The server packet definitions.</param> public PacketAnalyzer(PacketDefinitions clientPacketDefinitions, PacketDefinitions serverPacketDefinitions) { this.clientPacketDefinitions = clientPacketDefinitions; this.serverPacketDefinitions = serverPacketDefinitions; }
/// <summary> /// Extracts the field value from this packet. /// </summary> /// <param name="data">The data.</param> /// <param name="field">The field definition.</param> /// <param name="packet">The packet.</param> /// <param name="definitions">The definitions.</param> /// <returns> /// The value of the field. /// </returns> private string ExtractFieldValue(Span <byte> data, Field field, PacketDefinition packet, PacketDefinitions definitions) { var fieldSize = field.GetFieldSizeInBytes(); if (field.Type == FieldType.String && field.Index < data.Length) { return(data.ExtractString(field.Index, fieldSize ?? int.MaxValue, Encoding.UTF8)); } if (field.Type == FieldType.Binary && field.Index < data.Length) { return(fieldSize.HasValue ? data.Slice(field.Index, fieldSize.Value).AsString() : data.Slice(field.Index).AsString()); } if (data.Length < field.Index + fieldSize) { return(string.Empty); } return(field.Type switch { FieldType.Byte => data.Slice(field.Index) .GetByteValue(field.LengthSpecified ? field.Length : 8, field.LeftShifted) .ToString(), FieldType.Boolean => data.Slice(field.Index).GetBoolean(field.LeftShifted).ToString(), FieldType.IntegerLittleEndian => ReadUInt32LittleEndian(data.Slice(field.Index)).ToString(), FieldType.IntegerBigEndian => ReadUInt32BigEndian(data.Slice(field.Index)).ToString(), FieldType.ShortLittleEndian => ReadUInt16LittleEndian(data.Slice(field.Index)).ToString(), FieldType.ShortBigEndian => ReadUInt16BigEndian(data.Slice(field.Index)).ToString(), FieldType.LongLittleEndian => ReadUInt64LittleEndian(data.Slice(field.Index)).ToString(), FieldType.LongBigEndian => ReadUInt64BigEndian(data.Slice(field.Index)).ToString(), FieldType.Enum => this.ExtractEnumValue(data, field, packet, definitions), FieldType.StructureArray => this.ExtractStructureArrayValues(data, field, packet, definitions), FieldType.Float => BitConverter.ToSingle(data.Slice(field.Index)).ToString(CultureInfo.InvariantCulture), _ => string.Empty });
/// <summary> /// Extracts the field value from this packet or returns an error message, if it couldn't be extracted. /// </summary> /// <param name="data">The data.</param> /// <param name="field">The field definition.</param> /// <param name="packet">The packet.</param> /// <param name="definitions">The definitions.</param> /// <returns> /// The value of the field or the error message. /// </returns> private string ExtractFieldValueOrGetError(Span <byte> data, Field field, PacketDefinition packet, PacketDefinitions definitions) { try { return(this.ExtractFieldValue(data, field, packet, definitions)); } catch (Exception e) { return($"{e.GetType().Name}: {e.Message}"); } }
private string ExtractEnumValue(Span <byte> data, Field field, PacketDefinition packet, PacketDefinitions definitions) { var byteValue = data.Slice(field.Index).GetByteValue(field.LengthSpecified ? field.Length : 8, field.LeftShifted); var enumDefinition = packet.Enums?.FirstOrDefault(e => e.Name == field.TypeName) ?? definitions.Enums?.FirstOrDefault(e => e.Name == field.TypeName) ?? this.commonDefinitions?.Enums?.FirstOrDefault(e => e.Name == field.TypeName); var enumValue = enumDefinition?.Values.FirstOrDefault(v => v.Value == byteValue); return($"{data[field.Index]} ({enumValue?.Name ?? "unknown"})"); }
private string ExtractStructureArrayValues(Span <byte> data, Field field, PacketDefinition packet, PacketDefinitions definitions) { var type = packet.Structures?.FirstOrDefault(s => s.Name == field.TypeName) ?? definitions.Structures?.FirstOrDefault(s => s.Name == field.TypeName) ?? this.commonDefinitions.Structures?.FirstOrDefault(s => s.Name == field.TypeName); if (type == null) { return(data.Slice(field.Index).AsString()); } var countField = packet.Fields.FirstOrDefault(f => f.Name == field.ItemCountField) ?? packet.Structures?.SelectMany(s => s.Fields).FirstOrDefault(f => f.Name == field.ItemCountField); int count = int.Parse(this.ExtractFieldValue(data, countField, packet, definitions)); if (count == 0) { return(string.Empty); } var typeLength = type.Length > 0 ? type.Length : this.DetermineFixedStructLength(data, field, type, count); var stringBuilder = new StringBuilder(); var restData = data.Slice(field.Index); for (int i = 0; i < count; i++) { var currentLength = typeLength ?? this.DetermineDynamicStructLength(restData, type, packet); var elementData = restData.Slice(0, currentLength); restData = restData.Slice(currentLength); stringBuilder.Append(Environment.NewLine) .Append(field.Name + $"[{i}]:"); stringBuilder.Append(Environment.NewLine) .Append(" Raw: ").Append(elementData.AsString()); foreach (var structField in type.Fields) { stringBuilder.Append(Environment.NewLine) .Append(" ").Append(structField.Name).Append(": ").Append(this.ExtractFieldValue(elementData, structField, packet, definitions)); } } return(stringBuilder.ToString()); }
/// <summary> /// Extracts the field value from this packet. /// </summary> /// <param name="data">The data.</param> /// <param name="field">The field definition.</param> /// <param name="packet">The packet.</param> /// <param name="definitions">The definitions.</param> /// <returns> /// The value of the field. /// </returns> private string ExtractFieldValue(Span <byte> data, Field field, PacketDefinition packet, PacketDefinitions definitions) { var fieldSize = field.GetFieldSizeInBytes(); if (field.Type == FieldType.String && field.Index < data.Length) { return(data.ExtractString(field.Index, fieldSize ?? int.MaxValue, Encoding.UTF8)); } if (field.Type == FieldType.Binary && field.Index < data.Length) { return(fieldSize.HasValue ? data.Slice(field.Index, fieldSize.Value).AsString() : data.Slice(field.Index).AsString()); } if (data.Length < field.Index + fieldSize) { return(string.Empty); } switch (field.Type) { case FieldType.Byte: return(data.Slice(field.Index).GetByteValue(field.LengthSpecified ? field.Length : 8, field.LeftShifted).ToString()); case FieldType.Boolean: return(data.Slice(field.Index).GetBoolean(field.LeftShifted).ToString()); case FieldType.Integer: return(data.Slice(field.Index).GetIntegerLittleEndian().ToString()); case FieldType.IntegerBigEndian: return(data.Slice(field.Index).GetIntegerBigEndian().ToString()); case FieldType.Short: return(data.Slice(field.Index).GetShortLittleEndian().ToString()); case FieldType.ShortBigEndian: return(data.Slice(field.Index).GetShortBigEndian().ToString()); case FieldType.Long: return(data.Slice(field.Index).GetLongLittleEndian().ToString()); case FieldType.LongBigEndian: return(data.Slice(field.Index).GetLongBigEndian().ToString()); case FieldType.Enum: return(this.ExtractEnumValue(data, field, packet, definitions)); case FieldType.StructureArray: return(this.ExtractStructureArrayValues(data, field, packet, definitions)); case FieldType.Float: return(BitConverter.ToSingle(data.Slice(field.Index)).ToString(CultureInfo.InvariantCulture)); default: return(string.Empty); } }