mirror of
https://github.com/crskycode/GARbro.git
synced 2025-01-11 04:29:15 +08:00
(QLIE): updated 'FilePackVer3.1' archives support (#84)
This commit is contained in:
parent
8724e8131c
commit
f40226866c
@ -38,10 +38,12 @@ namespace GameRes.Formats.Qlie
|
||||
{
|
||||
internal class QlieEntry : PackedEntry
|
||||
{
|
||||
public bool IsEncrypted;
|
||||
public int EncryptionMethod;
|
||||
public uint Hash;
|
||||
public byte[] RawName;
|
||||
|
||||
public bool IsEncrypted { get { return EncryptionMethod != 0; } }
|
||||
|
||||
/// <summary>
|
||||
/// Data from a separate key file "key.fkey" that comes with installed game.
|
||||
/// null if not used.
|
||||
@ -153,7 +155,7 @@ namespace GameRes.Formats.Qlie
|
||||
return null;
|
||||
entry.UnpackedSize = index.ReadUInt32(); // [+0C]
|
||||
entry.IsPacked = 0 != index.ReadInt32(); // [+10]
|
||||
entry.IsEncrypted = 0 != index.ReadInt32(); // [+14]
|
||||
entry.EncryptionMethod = index.ReadInt32(); // [+14]
|
||||
entry.Hash = index.ReadUInt32(); // [+18]
|
||||
entry.KeyFile = key_file;
|
||||
if (3 == pack_version.Major && use_pack_keyfile && entry.Name.Contains ("pack_keyfile"))
|
||||
@ -330,6 +332,16 @@ namespace GameRes.Formats.Qlie
|
||||
return File.ReadAllBytes (name);
|
||||
}
|
||||
}
|
||||
var pattern = VFS.CombinePath (dir_name, @"..\*.exe");
|
||||
foreach (var exe_file in VFS.GetFiles (pattern))
|
||||
{
|
||||
using (var exe = new ExeFile.ResourceAccessor (exe_file.Name))
|
||||
{
|
||||
var reskey = exe.GetResource ("RESKEY", "#10");
|
||||
if (reskey != null)
|
||||
return reskey;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Qlie
|
||||
{
|
||||
@ -285,13 +286,28 @@ namespace GameRes.Formats.Qlie
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe void DecryptV1 (byte* data, int length, QlieEntry entry)
|
||||
{
|
||||
var file_name = entry.Name;
|
||||
uint hash = 0x85F532;
|
||||
uint seed = 0x33F641;
|
||||
@ -306,34 +322,66 @@ namespace GameRes.Formats.Qlie
|
||||
+ hash + (hash ^ (uint)length ^ 0x8F32DCu));
|
||||
seed = 9 * (seed & 0xFFFFFF);
|
||||
var table = GenerateTable (0x20, seed); // originally 0x2C, 12 dwords not used
|
||||
unsafe
|
||||
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)
|
||||
{
|
||||
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 t = table[k] | (ulong)table[k+1] << 32;
|
||||
hash64 = MMX.PAddD (hash64 ^ t, t);
|
||||
|
||||
ulong d = data64[i] ^ hash64;
|
||||
data64[i] = d;
|
||||
ulong d = data64[i] ^ hash64;
|
||||
data64[i] = d;
|
||||
|
||||
hash64 = MMX.PAddB (hash64, d) ^ d;
|
||||
hash64 = MMX.PAddW (MMX.PSllD (hash64, 1), d);
|
||||
hash64 = MMX.PAddB (hash64, d) ^ d;
|
||||
hash64 = MMX.PAddW (MMX.PSllD (hash64, 1), d);
|
||||
|
||||
k = (k + 2) & 0x1F;
|
||||
}
|
||||
}
|
||||
k = (k + 2) & 0x1F;
|
||||
}
|
||||
}
|
||||
|
||||
static uint[] GenerateTable (int length, uint seed)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static uint[] GenerateTable (int length, uint seed, uint key = 0x8DF21431u)
|
||||
{
|
||||
const uint key = 0x8DF21431u;
|
||||
var table = new uint[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
@ -343,5 +391,30 @@ namespace GameRes.Formats.Qlie
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
byte[] GenerateKeyData (byte[] key_file)
|
||||
{
|
||||
var key_data = new byte[0x400];
|
||||
for (int i = 0; i < 0x100; ++i)
|
||||
{
|
||||
int hash;
|
||||
if (0 != (i % 3))
|
||||
hash = (i + 7) * -(i + 3);
|
||||
else
|
||||
hash = (i + 7) * (i + 3);
|
||||
LittleEndian.Pack (hash, key_data, i * 4);
|
||||
}
|
||||
if (key_file != null && key_file.Length >= 128)
|
||||
{
|
||||
int k = key_file[49] % 73 + 128;
|
||||
int l = key_file[79] % 7 + 7;
|
||||
for (int i = 0; i < key_data.Length; ++i)
|
||||
{
|
||||
k = (k + l) % key_file.Length;
|
||||
key_data[i] ^= key_file[k];
|
||||
}
|
||||
}
|
||||
return key_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@ -744,6 +744,7 @@ Zetsuboushi<br/>
|
||||
<tr><td>*.pack</td><td><tt>FilePackVer1.0</tt><br/><tt>FilePackVer2.0</tt><br/><tt>FilePackVer3.0</tt><br/><tt>FilePackVer3.1</tt></td><td></td><td rowspan="3">QLIE</td><td rowspan="3">
|
||||
Amanatsu Adolesence Trial 2<br/>
|
||||
Bishoujo Mangekyou -Kami ga Tsukuritamouta Shoujo-tachi-<br/>
|
||||
Bishoujo Mangekyou -Tsumi to Batsu no Shoujo-<br/>
|
||||
Harem Hospital<br/>
|
||||
Hidamari Basket<br/>
|
||||
Kikan Bakumatsu Ibun Last Cavalier<br/>
|
||||
|
@ -11,7 +11,7 @@
|
||||
</Notes>
|
||||
</Release>
|
||||
<FormatsData>
|
||||
<FileVersion>75</FileVersion>
|
||||
<FileVersion>76</FileVersion>
|
||||
<Url>https://github.com/morkt/GARbro/raw/master/ArcFormats/Resources/Formats.dat</Url>
|
||||
<Requires>
|
||||
<Assembly Name="ArcFormats" Version="1.2.33.1392"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user