public KoiStream(string name, IReadableSegment contents, ILogger logger) : base(name, contents) { var reader = contents.CreateReader(); logger.Debug(Tag, "Reading koi stream header..."); uint magic = reader.ReadUInt32(); if (magic != Signature) { logger.Warning(Tag, $"Koi stream data does not start with a valid signature (Expected 0x{Signature:X4} but read 0x{magic:X4})."); } uint mdCount = reader.ReadUInt32(); uint strCount = reader.ReadUInt32(); uint expCount = reader.ReadUInt32(); logger.Debug(Tag, $"Reading {mdCount} references..."); for (int i = 0; i < mdCount; i++) { uint id = Utils.ReadCompressedUInt(ref reader); uint token = Utils.FromCodedToken(Utils.ReadCompressedUInt(ref reader)); References.Add(id, new MetadataToken(token)); } logger.Debug(Tag, $"Reading {strCount} strings..."); for (int i = 0; i < strCount; i++) { uint id = Utils.ReadCompressedUInt(ref reader); int length = (int)Utils.ReadCompressedUInt(ref reader); byte[] buffer = new byte[length * 2]; reader.ReadBytes(buffer, 0, buffer.Length); Strings.Add(id, Encoding.Unicode.GetString(buffer)); } logger.Debug(Tag, $"Reading {expCount} exports..."); for (int i = 0; i < expCount; i++) { uint id = Utils.ReadCompressedUInt(ref reader); var exportInfo = VMExportInfo.FromReader(ref reader); // Exports in KoiVM either point to entrypoints of virtualised methods, or just act as a descriptor // for methods that are intra linked through instructions like ldftn. if (exportInfo.IsSignatureOnly) { logger.Debug(Tag, $"Export {id} maps to a method signature of an intra-linked method."); } else { logger.Debug(Tag, $"Export {id} maps to function_{exportInfo.EntrypointAddress:X4}."); } Exports.Add(id, exportInfo); } }
public static KoiStream FromReadingContext(ReadingContext context, ILogger logger) { var reader = context.Reader; var result = new KoiStream { StartOffset = reader.Position }; logger.Debug(Tag, "Reading koi stream header..."); uint magic = reader.ReadUInt32(); if (magic != Signature) { logger.Warning(Tag, $"Koi stream data does not start with a valid signature (Expected 0x{Signature:X4} but read 0x{magic:X4})."); } uint mdCount = reader.ReadUInt32(); uint strCount = reader.ReadUInt32(); uint expCount = reader.ReadUInt32(); logger.Debug(Tag, $"Reading {mdCount} references..."); for (int i = 0; i < mdCount; i++) { uint id = Utils.ReadCompressedUInt(reader); uint token = Utils.FromCodedToken(Utils.ReadCompressedUInt(reader)); result.References.Add(id, new MetadataToken(token)); } logger.Debug(Tag, $"Reading {strCount} strings..."); for (int i = 0; i < strCount; i++) { uint id = Utils.ReadCompressedUInt(reader); int length = (int)Utils.ReadCompressedUInt(reader); result.Strings.Add(id, Encoding.Unicode.GetString(reader.ReadBytes(length * 2))); } logger.Debug(Tag, $"Reading {expCount} exports..."); for (int i = 0; i < expCount; i++) { uint id = Utils.ReadCompressedUInt(reader); var exportInfo = VMExportInfo.FromReader(reader); // Exports in KoiVM either point to entrypoints of virtualised methods, or just act as a descriptor // for methods that are intra linked through instructions like ldftn. if (exportInfo.IsSignatureOnly) { logger.Debug(Tag, $"Export {id} maps to a method signature of an intra-linked method."); } else { logger.Debug(Tag, $"Export {id} maps to function_{exportInfo.EntrypointAddress:X4}."); } result.Exports.Add(id, exportInfo); } reader.Position = reader.StartPosition; result.Data = reader.ReadBytes((int)reader.Length); return(result); }