public static IEnumerable <PotentialArray> FindArrays(ReadOnlyMemory <byte> payload) { using var reader = new GameBinaryReader(payload.GetArray()); for (var i = 0; i < reader.Length; i++) { reader.Position = i; if (!reader.CanRead(sizeof(ushort) * 2)) { break; } var countPos = reader.Position; var count = reader.ReadUInt16(); var offsetPos = reader.Position; var offset = reader.ReadOffset(); if (count == 0 || (count * (sizeof(ushort) * 2 + sizeof(byte)) + sizeof(ushort) * 2) > reader.Length) { continue; } var positions = new HashSet <int> { countPos, countPos + sizeof(byte), offsetPos, offsetPos + sizeof(byte), }; var elems = new List <PotentialArrayElement>(); var good = true; var last = offsetPos; var next = offset; while (next != -PacketHeader.HeaderSize) { if (!(good = next >= 0 && next > last && next <= reader.Length - sizeof(ushort) * 2 - sizeof(byte))) { break; } last = next + sizeof(ushort) * 2; reader.Position = next; var herePos = reader.Position; var here = reader.ReadOffset(); if (!(good = here == herePos && here == next && positions.Add(herePos) && positions.Add(herePos + sizeof(byte)))) { break; } var nextPos = reader.Position; next = reader.ReadOffset(); if (!(good = positions.Add(nextPos) && positions.Add(nextPos + sizeof(byte)))) { break; } elems.Add(new PotentialArrayElement(here, nextPos, next == -PacketHeader.HeaderSize ? 0 : next)); } if (good && elems.Count == count) { yield return(new PotentialArray(countPos, count, offsetPos, offset, elems)); } } }
void DeserializeObject(GameBinaryReader reader, object target) { foreach (var info in GetPacketInfo(target.GetType()).Fields.Cast <ReflectionPacketFieldInfo>()) { if (info.IsByteArray) { var offset = reader.ReadOffset(); var count = reader.ReadUInt16(); var list = (List <byte>)info.Property.GetValue(target); list.Clear(); if (count == 0) { continue; } reader.Seek(offset, (r, op) => list.AddRange(r.ReadBytes(count))); } else if (info.IsArray) { var count = reader.ReadUInt16(); var offset = reader.ReadOffset(); var list = (IList)info.Property.GetValue(target); list.Clear(); if (count == 0) { continue; } var next = offset; for (var i = 0; i < count; i++) { reader.Seek(next, (r, op) => { r.ReadOffset(); next = r.ReadOffset(); var elem = info.ElementConstructor(); DeserializeObject(r, elem); list.Add(elem); }); } } else if (info.IsString) { var offset = reader.ReadOffset(); info.Property.SetValue(target, reader.Seek(offset, (r, op) => r.ReadString())); } else { var val = info.PrimitiveDeserializer(reader); info.EnumValidator?.Invoke(val); info.Property.SetValue(target, val); } } }
public static IEnumerable <PotentialString> FindStrings(ReadOnlyMemory <byte> payload, bool whiteSpace, bool control, int minLength) { using var reader = new GameBinaryReader(payload.GetArray()); for (var i = 0; i < reader.Length; i++) { reader.Position = i; if (!reader.CanRead(sizeof(ushort))) { break; } var offsetPos = reader.Position; var offset = reader.ReadOffset(); if (offset < 0 || offset < offsetPos + sizeof(ushort) || offset > reader.Length - sizeof(char)) { continue; } reader.Position = offset; string str; try { str = reader.ReadString(); GameBinaryReader.Encoding.GetString(GameBinaryReader.Encoding.GetBytes(str)); } catch (Exception e) when(IsStringException(e)) { continue; } if (!whiteSpace && string.IsNullOrWhiteSpace(str)) { continue; } if (minLength != 0 && str.Length < minLength) { continue; } var hasBadChars = str.Any(c => { var cat = char.GetUnicodeCategory(c); return(cat == UnicodeCategory.Control || cat == UnicodeCategory.Format || cat == UnicodeCategory.OtherNotAssigned || cat == UnicodeCategory.PrivateUse || cat == UnicodeCategory.Surrogate); }); if (!control && hasBadChars) { continue; } yield return(new PotentialString(offsetPos, offset, str)); } }