Esempio n. 1
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;
                    }
                }
            }
        }
Esempio n. 2
0
        private void DecryptV3(byte[] data, int offset, int length, byte[] file_name,
                                uint arc_hash, byte[] key_file, byte[] game_key)
        {
            // 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;

            uint hash = 0x85F532;
            uint seed = 0x33F641;

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

            seed += arc_hash ^ (7 * ((uint)data.Length & 0xFFFFFF) + (uint)data.Length
                                + hash + (hash ^ (uint)data.Length ^ 0x8F32DCu));
            seed = 9 * (seed & 0xFFFFFF);

            if (game_key != null)
                seed ^= 0x453A;

            var mt = new QlieMersenneTwister (seed);
            if (key_file != null)
                mt.XorState (key_file);
            if (game_key != null)
                mt.XorState (game_key);

            // 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;
                    }
                }
            }
        }