mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 07:34:00 +08:00
(QLIE): try different decryptors for version 1 archives.
This commit is contained in:
parent
2f314aa687
commit
b6d29c4075
@ -110,68 +110,38 @@ namespace GameRes.Formats.Qlie
|
|||||||
if (!file.View.AsciiEqual (index_offset, "FilePackVer")
|
if (!file.View.AsciiEqual (index_offset, "FilePackVer")
|
||||||
|| '.' != file.View.ReadByte (index_offset+0xC))
|
|| '.' != file.View.ReadByte (index_offset+0xC))
|
||||||
return null;
|
return null;
|
||||||
var pack_version = new Version (file.View.ReadByte (index_offset+0xB) - '0',
|
using (var index = new PackIndexReader (this, file, index_offset))
|
||||||
file.View.ReadByte (index_offset+0xD) - '0');
|
|
||||||
int count = file.View.ReadInt32 (index_offset+0x10);
|
|
||||||
if (!IsSaneCount (count))
|
|
||||||
return null;
|
|
||||||
index_offset = file.View.ReadInt64 (index_offset+0x14);
|
|
||||||
if (index_offset < 0 || index_offset >= file.MaxOffset)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] arc_key = null;
|
|
||||||
byte[] key_file = null;
|
|
||||||
bool use_pack_keyfile = false;
|
|
||||||
if (pack_version.Major >= 3)
|
|
||||||
{
|
{
|
||||||
key_file = FindKeyFile (file);
|
byte[] arc_key = null;
|
||||||
use_pack_keyfile = key_file != null;
|
byte[] key_file = null;
|
||||||
// currently, user is prompted to choose encryption scheme only if there's 'key.fkey' file found.
|
bool use_pack_keyfile = false;
|
||||||
if (use_pack_keyfile && pack_version.Minor == 0)
|
if (index.PackVersion.Major >= 3)
|
||||||
arc_key = QueryEncryption (file);
|
|
||||||
// use_pack_keyfile = null != arc_key;
|
|
||||||
}
|
|
||||||
var enc = QlieEncryption.Create (file, pack_version, arc_key);
|
|
||||||
|
|
||||||
bool read_pack_keyfile = 3 == pack_version.Major && use_pack_keyfile;
|
|
||||||
var name_buffer = new byte[0x100];
|
|
||||||
var dir = new List<Entry> (count);
|
|
||||||
using (var index = file.CreateStream (index_offset))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
{
|
||||||
int name_length = index.ReadUInt16();
|
key_file = FindKeyFile (file);
|
||||||
if (enc.IsUnicode)
|
use_pack_keyfile = key_file != null;
|
||||||
name_length *= 2;
|
// currently, user is prompted to choose encryption scheme only if there's 'key.fkey' file found.
|
||||||
if (name_length > name_buffer.Length)
|
if (use_pack_keyfile && index.PackVersion.Minor == 0)
|
||||||
name_buffer = new byte[name_length];
|
arc_key = QueryEncryption (file);
|
||||||
if (name_length != index.Read (name_buffer, 0, name_length))
|
// use_pack_keyfile = null != arc_key;
|
||||||
return null;
|
|
||||||
var name = enc.DecryptName (name_buffer, name_length);
|
|
||||||
var entry = Create<QlieEntry> (name);
|
|
||||||
if (use_pack_keyfile)
|
|
||||||
entry.RawName = name_buffer.Take (name_length).ToArray();
|
|
||||||
|
|
||||||
entry.Offset = index.ReadInt64(); // [+00]
|
|
||||||
entry.Size = index.ReadUInt32(); // [+08]
|
|
||||||
if (!entry.CheckPlacement (file.MaxOffset))
|
|
||||||
return null;
|
|
||||||
entry.UnpackedSize = index.ReadUInt32(); // [+0C]
|
|
||||||
entry.IsPacked = 0 != index.ReadInt32(); // [+10]
|
|
||||||
entry.EncryptionMethod = index.ReadInt32(); // [+14]
|
|
||||||
if (pack_version.Major > 1)
|
|
||||||
entry.Hash = index.ReadUInt32(); // [+18]
|
|
||||||
entry.KeyFile = key_file;
|
|
||||||
if (read_pack_keyfile && entry.Name.Contains ("pack_keyfile"))
|
|
||||||
{
|
|
||||||
// note that 'pack_keyfile' itself is encrypted using 'key.fkey' file contents.
|
|
||||||
key_file = ReadEntryBytes (file, entry, enc);
|
|
||||||
read_pack_keyfile = false;
|
|
||||||
}
|
|
||||||
dir.Add (entry);
|
|
||||||
}
|
}
|
||||||
|
var enc = QlieEncryption.Create (file, index.PackVersion, arc_key);
|
||||||
|
List<Entry> dir = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dir = index.Read (enc, key_file, use_pack_keyfile);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (index.PackVersion.Major == 1)
|
||||||
|
{
|
||||||
|
enc = new EncryptionV2();
|
||||||
|
dir = index.Read (enc, key_file, use_pack_keyfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (null == dir)
|
||||||
|
return null;
|
||||||
|
return new QlieArchive (file, this, dir, enc);
|
||||||
}
|
}
|
||||||
return new QlieArchive (file, this, dir, enc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
@ -184,7 +154,7 @@ namespace GameRes.Formats.Qlie
|
|||||||
return new BinMemoryStream (data, entry.Name);
|
return new BinMemoryStream (data, entry.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] ReadEntryBytes (ArcView file, QlieEntry entry, IEncryption enc)
|
internal byte[] ReadEntryBytes (ArcView file, QlieEntry entry, IEncryption enc)
|
||||||
{
|
{
|
||||||
var data = file.View.ReadBytes (entry.Offset, entry.Size);
|
var data = file.View.ReadBytes (entry.Offset, entry.Size);
|
||||||
if (entry.IsEncrypted)
|
if (entry.IsEncrypted)
|
||||||
@ -391,4 +361,85 @@ namespace GameRes.Formats.Qlie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal sealed class PackIndexReader : IDisposable
|
||||||
|
{
|
||||||
|
PackOpener m_fmt;
|
||||||
|
ArcView m_file;
|
||||||
|
Version m_pack_version;
|
||||||
|
int m_count;
|
||||||
|
long m_index_offset;
|
||||||
|
IBinaryStream m_index;
|
||||||
|
List<Entry> m_dir;
|
||||||
|
|
||||||
|
public Version PackVersion { get { return m_pack_version; } }
|
||||||
|
|
||||||
|
public PackIndexReader (PackOpener fmt, ArcView file, long index_offset)
|
||||||
|
{
|
||||||
|
m_fmt = fmt;
|
||||||
|
m_file = file;
|
||||||
|
m_pack_version = new Version (m_file.View.ReadByte (index_offset+0xB) - '0',
|
||||||
|
m_file.View.ReadByte (index_offset+0xD) - '0');
|
||||||
|
m_count = m_file.View.ReadInt32 (index_offset+0x10);
|
||||||
|
if (!ArchiveFormat.IsSaneCount (m_count))
|
||||||
|
throw new InvalidFormatException();
|
||||||
|
m_index_offset = m_file.View.ReadInt64 (index_offset+0x14);
|
||||||
|
if (index_offset < 0 || index_offset >= m_file.MaxOffset)
|
||||||
|
throw new InvalidFormatException();
|
||||||
|
m_index = m_file.CreateStream (m_index_offset);
|
||||||
|
m_dir = new List<Entry> (m_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] m_name_buffer = new byte[0x100];
|
||||||
|
|
||||||
|
public List<Entry> Read (IEncryption enc, byte[] key_file, bool use_pack_keyfile)
|
||||||
|
{
|
||||||
|
m_dir.Clear();
|
||||||
|
m_index.Position = 0;
|
||||||
|
bool read_pack_keyfile = 3 == m_pack_version.Major && use_pack_keyfile;
|
||||||
|
for (int i = 0; i < m_count; ++i)
|
||||||
|
{
|
||||||
|
int name_length = m_index.ReadUInt16();
|
||||||
|
if (enc.IsUnicode)
|
||||||
|
name_length *= 2;
|
||||||
|
if (name_length > m_name_buffer.Length)
|
||||||
|
m_name_buffer = new byte[name_length];
|
||||||
|
if (name_length != m_index.Read (m_name_buffer, 0, name_length))
|
||||||
|
return null;
|
||||||
|
var name = enc.DecryptName (m_name_buffer, name_length);
|
||||||
|
var entry = m_fmt.Create<QlieEntry> (name);
|
||||||
|
if (use_pack_keyfile)
|
||||||
|
entry.RawName = m_name_buffer.Take (name_length).ToArray();
|
||||||
|
|
||||||
|
entry.Offset = m_index.ReadInt64(); // [+00]
|
||||||
|
entry.Size = m_index.ReadUInt32(); // [+08]
|
||||||
|
if (!entry.CheckPlacement (m_file.MaxOffset))
|
||||||
|
return null;
|
||||||
|
entry.UnpackedSize = m_index.ReadUInt32(); // [+0C]
|
||||||
|
entry.IsPacked = 0 != m_index.ReadInt32(); // [+10]
|
||||||
|
entry.EncryptionMethod = m_index.ReadInt32(); // [+14]
|
||||||
|
if (m_pack_version.Major > 1)
|
||||||
|
entry.Hash = m_index.ReadUInt32(); // [+18]
|
||||||
|
entry.KeyFile = key_file;
|
||||||
|
if (read_pack_keyfile && entry.Name.Contains ("pack_keyfile"))
|
||||||
|
{
|
||||||
|
// note that 'pack_keyfile' itself is encrypted using 'key.fkey' file contents.
|
||||||
|
key_file = m_fmt.ReadEntryBytes (m_file, entry, enc);
|
||||||
|
read_pack_keyfile = false;
|
||||||
|
}
|
||||||
|
m_dir.Add (entry);
|
||||||
|
}
|
||||||
|
return m_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool m_disposed = false;
|
||||||
|
public void Dispose ()
|
||||||
|
{
|
||||||
|
if (!m_disposed)
|
||||||
|
{
|
||||||
|
m_index.Dispose();
|
||||||
|
m_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user