Exemplo n.º 1
0
 public override byte Decrypt(Xp3Entry entry, long offset, byte value)
 {
     return((byte)(value ^ entry.Hash));
 }
Exemplo n.º 2
0
 public override void Encrypt(Xp3Entry entry, long offset, byte[] values, int pos, int count)
 {
     Decrypt(entry, offset, values, pos, count);
 }
Exemplo n.º 3
0
 public override byte Decrypt(Xp3Entry entry, long offset, byte value)
 {
     return(value);
 }
Exemplo n.º 4
0
 public override void Encrypt(Xp3Entry entry, long offset, byte[] values, int pos, int count)
 {
     return;
 }
Exemplo n.º 5
0
 public override byte Decrypt(Xp3Entry entry, long offset, byte value)
 {
     return((byte)(value ^ (entry.Hash >> (int)((uint)offset % 5))));
 }
Exemplo n.º 6
0
        public override byte Decrypt(Xp3Entry entry, long offset, byte value)
        {
            byte key = (byte)entry.Hash;

            return(key != 0 && offset % key != 0 ? (byte)(value ^ key) : value);
        }
Exemplo n.º 7
0
 public override byte Decrypt(Xp3Entry entry, long offset, byte value)
 {
     return(offset < 5 ? value : (byte)(value ^ (entry.Hash >> 12)));
 }
Exemplo n.º 8
0
 public override byte Decrypt(Xp3Entry entry, long offset, byte value)
 {
     return((byte)((value ^ m_key) + 1));
 }
Exemplo n.º 9
0
 public override byte Decrypt(Xp3Entry entry, long offset, byte value)
 {
     return((byte)(value ^ KeyTable[offset & 0xFF]));
 }
Exemplo n.º 10
0
 public virtual void Encrypt(Xp3Entry entry, long offset, byte[] values, int pos, int count)
 {
     throw new NotImplementedException(Strings.arcStrings.MsgEncNotImplemented);
 }
Exemplo n.º 11
0
 public abstract void Decrypt(Xp3Entry entry, long offset, byte[] values, int pos, int count);
Exemplo n.º 12
0
 public override void Encrypt(Xp3Entry entry, long offset, byte[] buffer, int pos, int count)
 {
     base.Encrypt(entry, offset, buffer, pos, count);
     ProcessFirstBytes(entry, offset, buffer, pos, count);
 }
Exemplo n.º 13
0
        void EncryptedFileCopy(FileStream file, Xp3Entry xp3entry, Stream output, bool compress)
        {
            if (file.Length > int.MaxValue)
            {
                throw new FileSizeException();
            }

            using (var map = MemoryMappedFile.CreateFromFile(file, null, 0,
                                                             MemoryMappedFileAccess.Read, null, HandleInheritability.None, true))
            {
                uint unpacked_size = (uint)file.Length;
                xp3entry.UnpackedSize = (uint)unpacked_size;
                xp3entry.Size         = (uint)unpacked_size;
                using (var view = map.CreateViewAccessor(0, unpacked_size, MemoryMappedFileAccess.Read))
                {
                    var segment = new Xp3Segment {
                        IsCompressed = compress,
                        Offset       = output.Position,
                        Size         = unpacked_size,
                        PackedSize   = unpacked_size,
                    };
                    if (compress)
                    {
                        output = new ZLibStream(output, CompressionMode.Compress, CompressionLevel.Level9, true);
                    }
                    unsafe
                    {
                        byte[] read_buffer = new byte[81920];
                        byte * ptr         = view.GetPointer(0);
                        try
                        {
                            var  checksum         = new Adler32();
                            bool hash_after_crypt = xp3entry.Cipher.HashAfterCrypt;
                            if (!hash_after_crypt)
                            {
                                xp3entry.Hash = checksum.Update(ptr, (int)unpacked_size);
                            }
                            int offset    = 0;
                            int remaining = (int)unpacked_size;
                            while (remaining > 0)
                            {
                                int amount = Math.Min(remaining, read_buffer.Length);
                                remaining -= amount;
                                Marshal.Copy((IntPtr)(ptr + offset), read_buffer, 0, amount);
                                xp3entry.Cipher.Encrypt(xp3entry, offset, read_buffer, 0, amount);
                                if (hash_after_crypt)
                                {
                                    checksum.Update(read_buffer, 0, amount);
                                }
                                output.Write(read_buffer, 0, amount);
                                offset += amount;
                            }
                            if (hash_after_crypt)
                            {
                                xp3entry.Hash = checksum.Value;
                            }
                        }
                        finally
                        {
                            view.SafeMemoryMappedViewHandle.ReleasePointer();
                            if (compress)
                            {
                                var dest = (output as ZLibStream).BaseStream;
                                output.Dispose();
                                segment.PackedSize = (uint)(dest.Position - segment.Offset);
                                xp3entry.Size      = segment.PackedSize;
                            }
                            xp3entry.Segments.Add(segment);
                        }
                    }
                }
            }
        }
Exemplo n.º 14
0
        public override void Create(Stream output, IEnumerable <Entry> list, ResourceOptions options,
                                    EntryCallback callback)
        {
            var xp3_options = GetOptions <Xp3Options> (options);

            ICrypt scheme            = xp3_options.Scheme;
            bool   compress_index    = xp3_options.CompressIndex;
            bool   compress_contents = xp3_options.CompressContents;
            bool   retain_dirs       = xp3_options.RetainDirs;

            bool use_encryption = !(scheme is NoCrypt);

            using (var writer = new BinaryWriter(output, Encoding.ASCII, true))
            {
                writer.Write(s_xp3_header);
                if (2 == xp3_options.Version)
                {
                    writer.Write((long)0x17);
                    writer.Write((int)1);
                    writer.Write((byte)0x80);
                    writer.Write((long)0);
                }
                long index_pos_offset = writer.BaseStream.Position;
                writer.BaseStream.Seek(8, SeekOrigin.Current);

                int  callback_count = 0;
                var  used_names     = new HashSet <string>();
                var  dir            = new List <Xp3Entry>();
                long current_offset = writer.BaseStream.Position;
                foreach (var entry in list)
                {
                    if (null != callback)
                    {
                        callback(callback_count++, entry, arcStrings.MsgAddingFile);
                    }

                    string name = entry.Name;
                    if (!retain_dirs)
                    {
                        name = Path.GetFileName(name);
                    }
                    else
                    {
                        name = name.Replace(@"\", "/");
                    }
                    if (!used_names.Add(name))
                    {
                        Trace.WriteLine("duplicate name", entry.Name);
                        continue;
                    }

                    var xp3entry = new Xp3Entry {
                        Name        = name,
                        Cipher      = scheme,
                        IsEncrypted = use_encryption &&
                                      !(scheme.StartupTjsNotEncrypted && VFS.IsPathEqualsToFileName(name, "startup.tjs"))
                    };
                    bool compress = compress_contents && ShouldCompressFile(entry);
                    using (var file = File.Open(name, FileMode.Open, FileAccess.Read))
                    {
                        if (!xp3entry.IsEncrypted || 0 == file.Length)
                        {
                            RawFileCopy(file, xp3entry, output, compress);
                        }
                        else
                        {
                            EncryptedFileCopy(file, xp3entry, output, compress);
                        }
                    }

                    dir.Add(xp3entry);
                }

                long index_pos = writer.BaseStream.Position;
                writer.BaseStream.Position = index_pos_offset;
                writer.Write(index_pos);
                writer.BaseStream.Position = index_pos;

                using (var header = new BinaryWriter(new MemoryStream(dir.Count * 0x58), Encoding.Unicode))
                {
                    if (null != callback)
                    {
                        callback(callback_count++, null, arcStrings.MsgWritingIndex);
                    }

                    long dir_pos = 0;
                    foreach (var entry in dir)
                    {
                        header.BaseStream.Position = dir_pos;
                        header.Write((uint)0x656c6946);  // "File"
                        long header_size_pos = header.BaseStream.Position;
                        header.Write((long)0);
                        header.Write((uint)0x6f666e69);  // "info"
                        header.Write((long)(4 + 8 + 8 + 2 + entry.Name.Length * 2));
                        header.Write((uint)(use_encryption ? 0x80000000 : 0));
                        header.Write((long)entry.UnpackedSize);
                        header.Write((long)entry.Size);

                        header.Write((short)entry.Name.Length);
                        foreach (char c in entry.Name)
                        {
                            header.Write(c);
                        }

                        header.Write((uint)0x6d676573);  // "segm"
                        header.Write((long)0x1c);
                        var segment = entry.Segments.First();
                        header.Write((int)(segment.IsCompressed ? 1 : 0));
                        header.Write((long)segment.Offset);
                        header.Write((long)segment.Size);
                        header.Write((long)segment.PackedSize);

                        header.Write((uint)0x726c6461);  // "adlr"
                        header.Write((long)4);
                        header.Write((uint)entry.Hash);

                        dir_pos = header.BaseStream.Position;
                        long header_size = dir_pos - header_size_pos - 8;
                        header.BaseStream.Position = header_size_pos;
                        header.Write(header_size);
                    }

                    header.BaseStream.Position = 0;
                    writer.Write(compress_index);
                    long unpacked_dir_size = header.BaseStream.Length;
                    if (compress_index)
                    {
                        if (null != callback)
                        {
                            callback(callback_count++, null, arcStrings.MsgCompressingIndex);
                        }

                        long packed_dir_size_pos = writer.BaseStream.Position;
                        writer.Write((long)0);
                        writer.Write(unpacked_dir_size);

                        long dir_start = writer.BaseStream.Position;
                        using (var zstream = new ZLibStream(writer.BaseStream, CompressionMode.Compress,
                                                            CompressionLevel.Level9, true))
                            header.BaseStream.CopyTo(zstream);

                        long packed_dir_size = writer.BaseStream.Position - dir_start;
                        writer.BaseStream.Position = packed_dir_size_pos;
                        writer.Write(packed_dir_size);
                    }
                    else
                    {
                        writer.Write(unpacked_dir_size);
                        header.BaseStream.CopyTo(writer.BaseStream);
                    }
                }
            }
            output.Seek(0, SeekOrigin.End);
        }
Exemplo n.º 15
0
        public override ArcFile TryOpen(ArcView file)
        {
            long base_offset = 0;

            if (0x5a4d == file.View.ReadUInt16(0))  // 'MZ'
            {
                base_offset = SkipExeHeader(file);
            }
            if (!file.View.AsciiEqual(base_offset, SignatureBytes))
            {
                return(null);
            }
            long dir_offset = base_offset + file.View.ReadInt64(base_offset + 0x0b);

            if (dir_offset < 0x13 || dir_offset >= file.MaxOffset)
            {
                return(null);
            }
            if (0x80 == file.View.ReadUInt32(dir_offset))
            {
                dir_offset = base_offset + file.View.ReadInt64(dir_offset + 9);
                if (dir_offset < 0x13 || dir_offset >= file.MaxOffset)
                {
                    return(null);
                }
            }
            int header_type = file.View.ReadByte(dir_offset);

            if (0 != header_type && 1 != header_type)
            {
                return(null);
            }

            Stream header_stream;

            if (0 == header_type) // read unpacked header
            {
                long header_size = file.View.ReadInt64(dir_offset + 1);
                if (header_size > uint.MaxValue)
                {
                    return(null);
                }
                header_stream = file.CreateStream(dir_offset + 9, (uint)header_size);
            }
            else // read packed header
            {
                long packed_size = file.View.ReadInt64(dir_offset + 1);
                if (packed_size > uint.MaxValue)
                {
                    return(null);
                }
                long header_size = file.View.ReadInt64(dir_offset + 9);
                using (var input = file.CreateStream(dir_offset + 17, (uint)packed_size))
                    header_stream = ZLibCompressor.DeCompress(input);
            }

            var crypt_algorithm = new Lazy <ICrypt> (() => QueryCryptAlgorithm(file), false);

            var dir = new List <Entry>();

            dir_offset = 0;
            using (var header = new BinaryReader(header_stream, Encoding.Unicode))
                using (var filename_map = new FilenameMap())
                {
                    while (-1 != header.PeekChar())
                    {
                        uint entry_signature = header.ReadUInt32();
                        long entry_size      = header.ReadInt64();
                        if (entry_size < 0)
                        {
                            return(null);
                        }
                        dir_offset += 12 + entry_size;
                        if (0x656C6946 == entry_signature) // "File"
                        {
                            var entry = new Xp3Entry();
                            while (entry_size > 0)
                            {
                                uint section      = header.ReadUInt32();
                                long section_size = header.ReadInt64();
                                entry_size -= 12;
                                if (section_size > entry_size)
                                {
                                    break;
                                }
                                entry_size -= section_size;
                                long next_section_pos = header.BaseStream.Position + section_size;
                                switch (section)
                                {
                                case 0x6f666e69: // "info"
                                    if (entry.Size != 0 || !string.IsNullOrEmpty(entry.Name))
                                    {
                                        goto NextEntry; // ambiguous entry, ignore
                                    }
                                    entry.IsEncrypted = 0 != header.ReadUInt32();
                                    long file_size   = header.ReadInt64();
                                    long packed_size = header.ReadInt64();
                                    if (file_size >= uint.MaxValue || packed_size > uint.MaxValue || packed_size > file.MaxOffset)
                                    {
                                        goto NextEntry;
                                    }
                                    entry.IsPacked     = file_size != packed_size;
                                    entry.Size         = (uint)packed_size;
                                    entry.UnpackedSize = (uint)file_size;

                                    if (entry.IsEncrypted || ForceEncryptionQuery)
                                    {
                                        entry.Cipher = crypt_algorithm.Value;
                                    }
                                    else
                                    {
                                        entry.Cipher = NoCryptAlgorithm;
                                    }

                                    var name = entry.Cipher.ReadName(header);
                                    if (null == name)
                                    {
                                        goto NextEntry;
                                    }
                                    if (entry.Cipher.ObfuscatedIndex && ObfuscatedPathRe.IsMatch(name))
                                    {
                                        goto NextEntry;
                                    }
                                    if (filename_map.Count > 0)
                                    {
                                        name = filename_map.Get(entry.Hash, name);
                                    }
                                    if (name.Length > 0x100)
                                    {
                                        goto NextEntry;
                                    }
                                    entry.Name        = name;
                                    entry.Type        = FormatCatalog.Instance.GetTypeFromName(name);
                                    entry.IsEncrypted = !(entry.Cipher is NoCrypt) &&
                                                        !(entry.Cipher.StartupTjsNotEncrypted && "startup.tjs" == name);
                                    break;

                                case 0x6d676573: // "segm"
                                    int segment_count = (int)(section_size / 0x1c);
                                    if (segment_count > 0)
                                    {
                                        for (int i = 0; i < segment_count; ++i)
                                        {
                                            bool compressed          = 0 != header.ReadInt32();
                                            long segment_offset      = base_offset + header.ReadInt64();
                                            long segment_size        = header.ReadInt64();
                                            long segment_packed_size = header.ReadInt64();
                                            if (segment_offset > file.MaxOffset || segment_packed_size > file.MaxOffset)
                                            {
                                                goto NextEntry;
                                            }
                                            var segment = new Xp3Segment {
                                                IsCompressed = compressed,
                                                Offset       = segment_offset,
                                                Size         = (uint)segment_size,
                                                PackedSize   = (uint)segment_packed_size
                                            };
                                            entry.Segments.Add(segment);
                                        }
                                        entry.Offset = entry.Segments.First().Offset;
                                    }
                                    break;

                                case 0x726c6461: // "adlr"
                                    if (4 == section_size)
                                    {
                                        entry.Hash = header.ReadUInt32();
                                    }
                                    break;

                                default: // unknown section
                                    break;
                                }
                                header.BaseStream.Position = next_section_pos;
                            }
                            if (!string.IsNullOrEmpty(entry.Name) && entry.Segments.Any())
                            {
                                if (entry.Cipher.ObfuscatedIndex)
                                {
                                    DeobfuscateEntry(entry);
                                }
                                dir.Add(entry);
                            }
                        }
                        else if (entry_size > 7)
                        {
                            // 0x6E666E68 == entry_signature    // "hnfn"
                            // 0x6C696D73 == entry_signature    // "smil"
                            // 0x46696C65 == entry_signature    // "eliF"
                            // 0x757A7559 == entry_signature    // "Yuzu"
                            uint hash      = header.ReadUInt32();
                            int  name_size = header.ReadInt16();
                            if (name_size > 0)
                            {
                                entry_size -= 6;
                                if (name_size * 2 <= entry_size)
                                {
                                    var filename = new string (header.ReadChars(name_size));
                                    filename_map.Add(hash, filename);
                                }
                            }
                        }
NextEntry:
                        header.BaseStream.Position = dir_offset;
                    }
                }
            if (0 == dir.Count)
            {
                return(null);
            }
            var arc = new ArcFile(file, this, dir);

            try
            {
                if (crypt_algorithm.IsValueCreated)
                {
                    crypt_algorithm.Value.Init(arc);
                }
                return(arc);
            }
            catch
            {
                arc.Dispose();
                throw;
            }
        }