Example #1
0
        unsafe void DecryptV1(byte *data, int length, QlieEntry entry)
        {
            var  file_name = entry.Name;
            uint hash      = 0x85F532;
            uint seed      = 0x33F641;

            for (int i = 0; i < file_name.Length; i++)
            {
                hash += (uint)(file_name[i] << (i & 7));
                seed ^= hash;
            }

            seed += ArcKey ^ (7 * ((uint)length & 0xFFFFFF) + (uint)length
                              + hash + (hash ^ (uint)length ^ 0x8F32DCu));
            seed = 9 * (seed & 0xFFFFFF);
            var    table        = GenerateTable(0x20, seed); // originally 0x2C, 12 dwords not used
            ulong *data64       = (ulong *)data;
            int    qword_length = length / 8;
            uint   k            = 2 * (table[0xD] & 0xF);
            ulong  hash64       = table[6] | (ulong)table[7] << 32;

            for (int i = 0; i < qword_length; ++i)
            {
                ulong t = table[k] | (ulong)table[k + 1] << 32;
                hash64 = MMX.PAddD(hash64 ^ t, t);

                ulong d = data64[i] ^ hash64;
                data64[i] = d;

                hash64 = MMX.PAddB(hash64, d) ^ d;
                hash64 = MMX.PAddW(MMX.PSllD(hash64, 1), d);

                k = (k + 2) & 0x1F;
            }
        }
Example #2
0
        public override void DecryptEntry(byte[] data, int offset, int length, QlieEntry entry)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length > data.Length || offset > data.Length - length)
            {
                throw new ArgumentOutOfRangeException("length");
            }
            uint arc_key = ArcKey;

            ulong hash = 0xA73C5F9DA73C5F9Dul;
            ulong xor  = ((uint)length + arc_key) ^ 0xFEC9753Eu;

            xor |= xor << 32;
            unsafe
            {
                fixed(byte *raw = data)
                {
                    ulong *encoded = (ulong *)(raw + offset);

                    for (int i = 0; i < length / 8; ++i)
                    {
                        hash = MMX.PAddD(hash, 0xCE24F523CE24F523ul) ^ xor;
                        xor  = *encoded ^ hash;
                        *encoded++ = xor;
                    }
                }
            }
        }
Example #3
0
 public override void DecryptEntry(byte[] data, int offset, int length, QlieEntry entry)
 {
     if (0 == entry.EncryptionMethod)
     {
         return;
     }
     if (offset < 0)
     {
         throw new ArgumentOutOfRangeException("offset");
     }
     if (length > data.Length || offset > data.Length - length)
     {
         throw new ArgumentOutOfRangeException("length");
     }
     if (length < 8)
     {
         return;
     }
     unsafe
     {
         fixed(byte *raw_data = &data[offset])
         {
             if (1 == entry.EncryptionMethod)
             {
                 DecryptV1(raw_data, length, entry);
             }
             else
             {
                 DecryptV2(raw_data, length, entry);
             }
         }
     }
 }
Example #4
0
        private byte[] ReadEntryBytes(ArcView file, QlieEntry entry, uint hash, byte[] game_key)
        {
            var data = new byte[entry.Size];

            file.View.Read(entry.Offset, data, 0, entry.Size);
            if (entry.IsEncrypted)
            {
                if (entry.KeyFile != null)
                {
                    DecryptV3(data, 0, data.Length, entry.RawName, hash, entry.KeyFile, game_key);
                }
                else
                {
                    Decrypt(data, 0, data.Length, hash);
                }
            }
            if (entry.IsPacked)
            {
                var unpacked = Decompress(data);
                if (null != unpacked)
                {
                    data = unpacked;
                }
            }
            return(data);
        }
Example #5
0
        public override void DecryptEntry(byte[] data, int offset, int length, QlieEntry entry)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length > data.Length || offset > data.Length - length)
            {
                throw new ArgumentOutOfRangeException("length");
            }
            if (length < 8)
            {
                return;
            }

            var  file_name = entry.Name;
            uint hash      = 0x85F532;
            uint seed      = 0x33F641;

            for (int i = 0; i < file_name.Length; i++)
            {
                hash += (uint)(file_name[i] << (i & 7));
                seed ^= hash;
            }

            seed += ArcKey ^ (7 * ((uint)length & 0xFFFFFF) + (uint)length
                              + hash + (hash ^ (uint)length ^ 0x8F32DCu));
            seed = 9 * (seed & 0xFFFFFF);
            var table = GenerateTable(0x20, seed);  // originally 0x2C, 12 dwords not used

            unsafe
            {
                fixed(byte *raw_data = &data[offset])
                {
                    ulong *data64       = (ulong *)raw_data;
                    int    qword_length = length / 8;
                    uint   k            = 2 * (table[0xD] & 0xF);
                    ulong  hash64       = table[6] | (ulong)table[7] << 32;

                    for (int i = 0; i < qword_length; ++i)
                    {
                        ulong t = table[k] | (ulong)table[k + 1] << 32;
                        hash64 = MMX.PAddD(hash64 ^ t, t);

                        ulong d = data64[i] ^ hash64;
                        data64[i] = d;

                        hash64 = MMX.PAddB(hash64, d) ^ d;
                        hash64 = MMX.PAddW(MMX.PSllD(hash64, 1), d);

                        k = (k + 2) & 0x1F;
                    }
                }
            }
        }
Example #6
0
        private byte[] ReadEntryBytes(ArcView file, QlieEntry entry, IEncryption enc)
        {
            var data = file.View.ReadBytes(entry.Offset, entry.Size);

            if (entry.IsEncrypted)
            {
                enc.DecryptEntry(data, 0, data.Length, entry);
            }
            if (entry.IsPacked)
            {
                data = Decompress(data) ?? data;
            }
            return(data);
        }
Example #7
0
        unsafe void DecryptV2(byte *data, int length, QlieEntry entry)
        {
            var  file_name = entry.Name;
            uint hash      = 0x86F7E2;
            uint seed      = 0x4437F1;

            for (int i = 0; i < file_name.Length; i++)
            {
                hash += (uint)(file_name[i] << (i & 7));
                seed ^= hash;
            }

            seed += ArcKey ^ (13 * ((uint)length & 0xFFFFFF) + (uint)length
                              + hash + (hash ^ (uint)length ^ 0x56E213u));
            seed = 13 * (seed & 0xFFFFFF);
            var table    = GenerateTable(0x20, seed, 0x8A77F473u); // originally 0x40
            var key_data = GenerateKeyData(entry.KeyFile);

            ulong *data64       = (ulong *)data;
            int    qword_length = length / 8;
            int    k            = (8 * ((int)table[8] & 0xD)) & 0x7F;
            ulong  hash64       = table[6] | (ulong)table[7] << 32;

            for (int i = 0; i < qword_length; ++i)
            {
                int   t_index = 2 * (k & 0xF);
                ulong t       = table[t_index] | (ulong)table[t_index + 1] << 32;
                t     ^= LittleEndian.ToUInt64(key_data, 8 * k);
                hash64 = MMX.PAddD(hash64 ^ t, t);

                ulong d = data64[i] ^ hash64;
                data64[i] = d;

                hash64 = MMX.PAddB(hash64, d) ^ d;
                hash64 = MMX.PAddW(MMX.PSllD(hash64, 1), d);

                k = (k + 1) & 0x7F;
            }
        }
Example #8
0
 public abstract void DecryptEntry(byte[] data, int offset, int length, QlieEntry entry);
Example #9
0
        public override void DecryptEntry(byte[] data, int offset, int length, QlieEntry entry)
        {
            var key_file = entry.KeyFile;

            if (null == key_file)
            {
                base.DecryptEntry(data, offset, length, entry);
                return;
            }
            // play it safe with 'unsafe' sections
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length > data.Length || offset > data.Length - length)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            if (length < 8)
            {
                return;
            }

            var  file_name = entry.RawName;
            uint hash      = 0x85F532;
            uint seed      = 0x33F641;

            for (uint i = 0; i < file_name.Length; i++)
            {
                hash += (i & 0xFF) * file_name[i];
                seed ^= hash;
            }

            seed += ArcKey ^ (7 * ((uint)length & 0xFFFFFF) + (uint)length
                              + hash + (hash ^ (uint)length ^ 0x8F32DCu));
            seed = 9 * (seed & 0xFFFFFF);

            if (GameKeyData != null)
            {
                seed ^= 0x453A;
            }

            var mt = new QlieMersenneTwister(seed);

            if (key_file != null)
            {
                mt.XorState(key_file);
            }
            if (GameKeyData != null)
            {
                mt.XorState(GameKeyData);
            }

            // game code fills dword[41] table, but only the first 16 qwords are used
            ulong[] table = new ulong[16];
            for (int i = 0; i < table.Length; ++i)
            {
                table[i] = mt.Rand64();
            }

            // compensate for 9 discarded dwords
            for (int i = 0; i < 9; ++i)
            {
                mt.Rand();
            }

            ulong hash64 = mt.Rand64();
            uint  t      = mt.Rand() & 0xF;

            unsafe
            {
                fixed(byte *raw_data = &data[offset])
                {
                    ulong *data64       = (ulong *)raw_data;
                    int    qword_length = length / 8;

                    for (int i = 0; i < qword_length; ++i)
                    {
                        hash64 = MMX.PAddD(hash64 ^ table[t], table[t]);

                        ulong d = data64[i] ^ hash64;
                        data64[i] = d;

                        hash64 = MMX.PAddB(hash64, d) ^ d;
                        hash64 = MMX.PAddW(MMX.PSllD(hash64, 1), d);

                        t++;
                        t &= 0xF;
                    }
                }
            }
        }
Example #10
0
 private byte[] ReadEntryBytes(ArcView file, QlieEntry entry, uint hash, byte[] game_key)
 {
     var data = file.View.ReadBytes (entry.Offset, entry.Size);
     if (entry.IsEncrypted)
     {
         if (entry.KeyFile != null)
             DecryptV3 (data, 0, data.Length, entry.RawName, hash, entry.KeyFile, game_key);
         else
             Decrypt (data, 0, data.Length, hash);
     }
     if (entry.IsPacked)
     {
         var unpacked = Decompress (data);
         if (null != unpacked)
             data = unpacked;
     }
     return data;
 }