Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OverflowException when trying to inflate. #1

Open
AraHaan opened this issue Jan 4, 2018 · 4 comments
Open

OverflowException when trying to inflate. #1

AraHaan opened this issue Jan 4, 2018 · 4 comments

Comments

@AraHaan
Copy link

AraHaan commented Jan 4, 2018

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;
        }
    }
}
@philippelatulippe
Copy link
Owner

Hi! Thanks for the bug report and fix. Unfortunately I'm not the author of this library, and I haven't coded in C# for years. I only put it on github so that I could distribute a small hack I made (which I kept in a branch). I suggest you fork this repository and fix it there. If you do, I'll update the readme of my repository so that it redirects developers to the fork.

@AraHaan
Copy link
Author

AraHaan commented Dec 21, 2018

@philippelatulippe Mind updating your readme to point to my zlib.managed fork?

@AraHaan
Copy link
Author

AraHaan commented Apr 14, 2020

@philippelatulippe the url to it is https://github.com/Elskom/zlib.managed/

I renamed the forked repository to match the fact that I had to rename the project just to publish it to nuget.org.

Also might have to mark this copy of zlib.net as archived repository, it cannot be deleted because obviously it would also delete any and all forks which would be bad.

@philippelatulippe
Copy link
Owner

It's great that you're maintaining this library, I've updated the readme to direct people to your fork. I won't archive this repo yet since I feel it's better to leave the issue tracker open and direct people who post to the right place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants