Skip to content

OverflowException when trying to inflate. #1

@AraHaan

Description

@AraHaan

When I try to decompress data using the entry.compressed_size or entry.uncompressed_size as input to my Decompression and Compression helper functions it seems to do this overflow from inside inflate itself.

I think this is because zlib.net was not updated to the absolute latest release of the C based zlib library that fixes the problem (it seems).

ZlibHelper.cs:

namespace Els_kom_Core.Classes
{
    /// <summary>
    /// Zlib Compression and Decompression Helper Class.
    /// </summary>
    public class ZlibHelper
    {
        /// <summary>
        /// Compresses data.
        /// </summary>
        public static void CompressData(byte[] inData, out byte[] outData, int size)
        {
            using (System.IO.MemoryStream outMemoryStream = new System.IO.MemoryStream())
            using (Zlib.ZOutputStream outZStream = new Zlib.ZOutputStream(outMemoryStream, Zlib.zlibConst.Z_DEFAULT_COMPRESSION))
            using (System.IO.Stream inMemoryStream = new System.IO.MemoryStream(inData))
            {
                CopyStream(inMemoryStream, outZStream, size);
                outZStream.finish();
                outData = outMemoryStream.ToArray();
            }
        }

        /// <summary>
        /// Decompresses data.
        /// </summary>
        public static void DecompressData(byte[] inData, out byte[] outData, int size)
        {
            using (System.IO.MemoryStream outMemoryStream = new System.IO.MemoryStream())
            using (Zlib.ZOutputStream outZStream = new Zlib.ZOutputStream(outMemoryStream))
            using (System.IO.Stream inMemoryStream = new System.IO.MemoryStream(inData))
            {
                CopyStream(inMemoryStream, outZStream, size);
                outZStream.finish();
                outData = outMemoryStream.ToArray();
            }
        }

        private static void CopyStream(System.IO.Stream input, System.IO.Stream output, int size)
        {
            byte[] buffer = new byte[size];
            int len;
            while ((len = input.Read(buffer, 0, size)) > 0)
            {
                output.Write(buffer, 0, len);
            }
            output.Flush();
        }
    }
}

Unpacker.cs:

namespace Els_kom_Core.Classes
{
    /// <summary>
    /// Unpacker Class for Els_kom that unpacks KOM files.
    /// </summary>
    public class Unpacker
    {
        private static System.Collections.Generic.Dictionary<int, int> KeyMap { get; set; } = new System.Collections.Generic.Dictionary<int, int>();

        /// <summary>
        /// Makes KOM V2 Entries for unpacking.
        /// </summary>
        private static System.Tuple<System.Collections.Generic.List<EntryVer2>, int> Make_entries_v2(int size, System.IO.BinaryReader reader)
        {
            System.Collections.Generic.List<EntryVer2> entries = new System.Collections.Generic.List<EntryVer2>();
            int relative_offseterr = size;
            for (int i = 0; i < size; i++)
            {
                string key = string.Empty;
                int originalsize;
                ReadInFile(reader, out originalsize);
                int compressedSize;
                ReadInFile(reader, out compressedSize);
                int offset;
                ReadInFile(reader, out offset);
                //SubFiles.Add(GetSafeString(key), new KOMSubFile(this, reader, 0x3C + size * 0x48));
                var entry = new EntryVer2(GetSafeString(key), originalsize, compressedSize, offset);
                entries.Add(entry);
                relative_offseterr += offset;
            }
            return System.Tuple.Create(entries, relative_offseterr);
        }

        /// <summary>
        /// Makes KOM V3 Entries for unpacking.
        /// </summary>
        private static System.Tuple<System.Collections.Generic.List<EntryVer3>, int> Make_entries_v3(string xmldata, int entry_count)
        {
            System.Collections.Generic.List<EntryVer3> entries = new System.Collections.Generic.List<EntryVer3>();
            int relative_offseterr = 0;
            var xml = System.Xml.Linq.XElement.Parse(xmldata);
            foreach (var fileElement in xml.Elements("File"))
            {
                var nameAttribute = fileElement.Attribute("Name");
                var name = nameAttribute?.Value ?? "no value";
                var sizeAttribute = fileElement.Attribute("Size");
                var size = sizeAttribute == null ? -1 : System.Convert.ToInt32(sizeAttribute.Value);
                var CompressedSizeAttribute = fileElement.Attribute("CompressedSize");
                var CompressedSize = CompressedSizeAttribute == null ? -1 : System.Convert.ToInt32(CompressedSizeAttribute.Value);
                var ChecksumAttribute = fileElement.Attribute("Checksum");
                var Checksum = ChecksumAttribute == null ? -1 : int.Parse(ChecksumAttribute.Value, System.Globalization.NumberStyles.HexNumber);
                var FileTimeAttribute = fileElement.Attribute("FileTime");
                var FileTime = FileTimeAttribute == null ? -1 : int.Parse(FileTimeAttribute.Value, System.Globalization.NumberStyles.HexNumber);
                var AlgorithmAttribute = fileElement.Attribute("Algorithm");
                var Algorithm = AlgorithmAttribute == null ? -1 : System.Convert.ToInt32(AlgorithmAttribute.Value);
                var entry = new EntryVer3(name, size, CompressedSize, Checksum, relative_offseterr, FileTime, Algorithm);
                entries.Add(entry);
                relative_offseterr += entry.compressed_size;
            }
            return System.Tuple.Create(entries, relative_offseterr);
        }

        /// <summary>
        /// Decrypt XML Header data in KOM V4 for KOM V3 Entry maker works out of the box.
        /// </summary>
        private static void DecryptCRCXml(int key, ref byte[] data, int length, System.Text.Encoding encoding)
        {
            if (!KeyMap.ContainsKey(key))
                return;

            string keyStr = KeyMap[key].ToString();
            string sha1Key = System.BitConverter.ToString(new System.Security.Cryptography.SHA1CryptoServiceProvider().ComputeHash(encoding.GetBytes(keyStr))).Replace("-", "");

            BlowFish blowfish = new BlowFish(sha1Key);
            data = blowfish.Decrypt(data, System.Security.Cryptography.CipherMode.ECB);
        }

        /// <summary>
        /// Common Unpack Code for KOM V3 and KOM V4.
        /// </summary>
        private static void Kom_v3_v4_unpack(string in_path, string out_path, int version)
        {
            System.IO.BinaryReader reader = new System.IO.BinaryReader(System.IO.File.OpenRead(in_path), System.Text.Encoding.ASCII);
            byte[] entry_count_buffer = new byte[System.Convert.ToInt32(KOM_DATA.KOM_ENTRY_COUNT_SIZE)];
            reader.BaseStream.Position += 52;
            entry_count_buffer = reader.ReadBytes(System.Convert.ToInt32(KOM_DATA.KOM_ENTRY_COUNT_SIZE));
            int compressed = 0;
            if (version > 3)
            {
                // do some reading for the CRC XML Data decompression or something?
            }
            int entry_count = System.BitConverter.ToInt32(entry_count_buffer, 0);
            byte[] file_timer_buffer = new byte[System.Convert.ToInt32(KOM_DATA.KOM_FILE_TIMER_SIZE)];
            reader.BaseStream.Position += 4;
            file_timer_buffer = reader.ReadBytes(System.Convert.ToInt32(KOM_DATA.KOM_FILE_TIMER_SIZE));
            byte[] xml_size_file_buffer = new byte[System.Convert.ToInt32(KOM_DATA.KOM_XML_SIZE_FILE_SIZE)];
            xml_size_file_buffer = reader.ReadBytes(System.Convert.ToInt32(KOM_DATA.KOM_XML_SIZE_FILE_SIZE));
            byte[] xmldatabuffer = new byte[System.BitConverter.ToInt32(xml_size_file_buffer, 0)];
            xmldatabuffer = reader.ReadBytes(System.BitConverter.ToInt32(xml_size_file_buffer, 0));
            if (version > 3)
            {
                DecryptCRCXml(compressed, ref xmldatabuffer, System.BitConverter.ToInt32(xml_size_file_buffer, 0), System.Text.Encoding.ASCII);
            }
            string xmldata = System.Text.Encoding.ASCII.GetString(xmldatabuffer);
            System.Tuple<System.Collections.Generic.List<EntryVer3>, int> entries = Make_entries_v3(xmldata, entry_count);
            foreach (var entry in entries.Item1)
            {
                // we iterate through every entry here and unpack the data.
                if (!System.IO.Directory.Exists(out_path))
                {
                    System.IO.Directory.CreateDirectory(out_path);
                }
                byte[] entrydata = reader.ReadBytes(entry.compressed_size);
                byte[] dec_entrydata;
                //entry.uncompressed_size
                //entry.compressed_size
                //entry.checksum
                //entry.relative_offset
                //entry.file_time
                if (entry.algorithm == 0)
                {
                    System.IO.FileStream entryfile = System.IO.File.Create(out_path + "\\" + entry.name);
                    MessageManager.ShowInfo(entry.uncompressed_size.ToString(), "Debug!");
                    ZlibHelper.DecompressData(entrydata, out dec_entrydata, entry.uncompressed_size);
                    entryfile.Write(dec_entrydata, 0, entry.uncompressed_size);
                    entryfile.Close();
                    entryfile.Dispose();
                }
                else
                {
                    if (entry.algorithm == 3)
                    {
                        // algorithm 3 code.
                        // this possible where plugin algorithm 3 unpack support be called?
                    }
                    else
                    {
                        // algorithm 2 code.
                        // this possible where plugin algorithm 2 unpack support be called?
                    }
                    System.IO.FileStream entryfile;
                    if (entrydata.Length == entry.uncompressed_size)
                    {
                        entryfile = System.IO.File.Create(out_path + "\\" + entry.name);
                    }
                    else
                    {
                        // data was not decompressed properly so lets just dump it as is.
                        entryfile = System.IO.File.Create(out_path + "\\" + entry.name + "." + entry.uncompressed_size + "." + entry.algorithm);
                    }
                    // for now until I can decompress this crap.
                    entryfile.Write(entrydata, 0, entry.compressed_size);
                    entryfile.Close();
                    entryfile.Dispose();
                }
            }
            reader.Close();
            reader.Dispose();
        }

        /// <summary>
        /// Unpacks V4 KOM Files.
        /// Note: V4 is V3 but with a encrypted CRC XML Data.
        /// </summary>
        public static void Kom_v4_unpack(string in_path, string out_path)
        {
            Kom_v3_v4_unpack(in_path, out_path, 4);
        }

        /// <summary>
        /// Unpacks V3 KOM Files.
        /// </summary>
        public static void Kom_v3_unpack(string in_path, string out_path)
        {
            Kom_v3_v4_unpack(in_path, out_path, 3);
        }

        /// <summary>
        /// Unpacks V2 KOM Files.
        /// </summary>
        public static void Kom_v2_unpack(string in_path, string out_path)
        {

            System.IO.BinaryReader reader = new System.IO.BinaryReader(System.IO.File.OpenRead(in_path), System.Text.Encoding.ASCII);
            reader.BaseStream.Position = 56;
            int size;
            ReadInFile(reader, out size);
            System.Tuple<System.Collections.Generic.List<EntryVer2>, int> entries = Make_entries_v2(0x3C + size * 0x48, reader);
            foreach (var entry in entries.Item1)
            {
                // iterate through every item in KOM V2.
                MessageManager.ShowInfo(entry.name, "Debug!");
                MessageManager.ShowInfo(entry.uncompressed_size.ToString(), "Debug!");
                MessageManager.ShowInfo(entry.compressed_size.ToString(), "Debug!");
                MessageManager.ShowInfo(entry.relative_offset.ToString(), "Debug!");
            }
            reader.Close();
            reader.Dispose();
        }

        private static string GetSafeString(string source)
        {
            if (source.Contains(new string(char.MinValue, 1)))
                return source.Substring(0, source.IndexOf(char.MinValue));

            return source;
        }

        internal static bool ReadInFile(System.IO.BinaryReader binaryReader, out string destString, int length, System.Text.Encoding encoding)
        {
            long position = binaryReader.BaseStream.Position;
            byte[] readBytes = binaryReader.ReadBytes(length);
            if ((binaryReader.BaseStream.Position - position) == length)
            {
                destString = encoding.GetString(readBytes);
                return true;
            }
            destString = null;
            return false;
        }

        internal static bool ReadInFile(System.IO.BinaryReader binaryReader, out int destInt)
        {
            long position = binaryReader.BaseStream.Position;
            int readInt = binaryReader.ReadInt32();
            if ((binaryReader.BaseStream.Position - position) == sizeof(int))
            {
                destInt = readInt;

                return true;
            }
            destInt = int.MinValue;
            return false;
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions