Compare commits

...

3 Commits
dev ... master

Author SHA1 Message Date
52c4f678db update
这个说明写不来...
2024-10-19 15:36:45 +08:00
857beaeab6 补上缺失的script加密代码 2024-10-19 15:35:23 +08:00
7a6ffec374 update 2024-10-19 13:52:38 +08:00
4 changed files with 110 additions and 29 deletions

View File

@ -63,7 +63,21 @@ namespace TmrHiroRepack
Encoding? shiftJis = provider.GetEncoding("shift-jis");
string[] files = Directory.GetFiles(folderPath);
short count = (short)files.Length; //文件数量
byte name_length = 0x16; //文件名长度(貌似固定16?)
string[] extensions = [".ogg", ".grd", ".srp"]; //需要移除的文件后缀因为这是Garbro添加的
int max_name_length = 0;
foreach (string file in files)
{
string fileName = Path.GetFileName(file);
foreach (var extension in extensions)
{
if (fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
{
fileName = fileName[..^extension.Length];
}
}
max_name_length = Math.Max(max_name_length, shiftJis.GetBytes(fileName).Length);
}
byte name_length = (byte)max_name_length; //文件名长度,每个封包值都不同
uint data_offset;
if (version == 1)
data_offset = 7 + ((uint)name_length + 8) * (uint)count; //Data区偏移
@ -72,8 +86,7 @@ namespace TmrHiroRepack
else
throw new Exception("Invalid Version");
long offset = 0; //Index区偏移
List<Index> indexs = new();
string[] extensions = { ".ogg", ".grd", ".srp" }; //需要移除的文件后缀因为这是Garbro添加的
List<Index> indexs = [];
foreach (string file in files)
{
Index i = new();
@ -85,8 +98,6 @@ namespace TmrHiroRepack
if (fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
{
fileName = fileName[..^extension.Length];
if (shiftJis.GetBytes(fileName).Length > name_length)
throw new Exception("Something Wrong, File name too long");
}
}
i.name = fileName;
@ -112,36 +123,55 @@ namespace TmrHiroRepack
}
//准备开写
string outputPath = Path.Combine(Path.GetDirectoryName(folderPath), Path.GetFileName(folderPath) + ".pac");
using (FileStream fs = new(outputPath, FileMode.Create))
using (BinaryWriter bw = new(fs))
using FileStream fs = new(outputPath, FileMode.Create);
using BinaryWriter bw = new(fs);
bw.Write(count);//文件数量
bw.Write(name_length);//文件名长度
bw.Write(data_offset);//Data区偏移
foreach (Index i in indexs)
{
bw.Write(count);//文件数量
bw.Write(name_length);//文件名长度
bw.Write(data_offset);//Data区偏移
foreach (Index i in indexs)
byte[] name = new byte[name_length];
Array.Copy(shiftJis.GetBytes(i.name), name, shiftJis.GetBytes(i.name).Length);
bw.Write(name);//文件名
if (version == 1)
{
byte[] name = new byte[name_length];
Array.Copy(shiftJis.GetBytes(i.name), name, shiftJis.GetBytes(i.name).Length);
bw.Write(name);//文件名
if (version == 1)
{
bw.Write(i.entryInfoV1.entryOffset);//文件偏移
bw.Write(i.entryInfoV1.entrySize);//文件大小
}
else if (version == 2)
{
bw.Write(i.entryInfoV2.entryOffset);//文件偏移
bw.Write(i.entryInfoV2.entrySize);//文件大小
}
bw.Write(i.entryInfoV1.entryOffset);//文件偏移
bw.Write(i.entryInfoV1.entrySize);//文件大小
}
foreach (string file in files)
else if (version == 2)
{
using (FileStream fs2 = new(file, FileMode.Open))
{
fs2.CopyTo(fs);
}
bw.Write(i.entryInfoV2.entryOffset);//文件偏移
bw.Write(i.entryInfoV2.entrySize);//文件大小
}
}
foreach (string file in files)
{
//检查是否是脚本文件(文件后缀.srp)
if (Path.GetExtension(file) == ".srp") // Script file detected
{
byte[] DecryptData = File.ReadAllBytes(file);
uint offset2 = 0;
int record_count = BitConverter.ToInt32(DecryptData, (int)offset2);
offset2 += 4;
for (int i = 0; i < record_count; i++)
{
ushort chunk_size = (ushort)(BitConverter.ToUInt16(DecryptData, (int)offset2) - 4); //我知道这里有潜在的问题但我不相信哪个游戏单个script文件有2G
offset2 += 6;
for (int j = 0; j < chunk_size; j++)
{
DecryptData[offset2] = Utils.RotByteL(DecryptData[offset2], 4);
offset2++;
}
}
bw.Write(DecryptData);
}
else
{
using FileStream fs2 = new(file, FileMode.Open);
fs2.CopyTo(fs);
}
}
return true;
}
}

View File

@ -122,5 +122,17 @@ namespace TmrHiroRepack
_ => throw new NotSupportedException($"Unsupported column Size: {v}"),
};
}
public static byte RotByteR(byte v, int count)
{
count &= 7;
return (byte)(v >> count | v << (8 - count));
}
public static byte RotByteL(byte v, int count)
{
count &= 7;
return (byte)(v << count | v >> (8 - count));
}
}
}

28
note/pac结构.txt Normal file
View File

@ -0,0 +1,28 @@
count short 2B
name_length uint 1B
data_offset uint 4B
如果data_offset=7+(name_length+8)*count ->v1
如果data_offset=7+(name_length+12)*count ->v2
index_offset=7
[ INDEX
name *string name_length
{ v1
entryOffset uint 4B (+data_offset *相对整个文件而言)
entrySize uint 4B
}
{ v2
entryOffset long 8B (+data_offset *同上)
entrySize uint 4B
}
]
[ DATA
]
文件处理
.ogg/.grd/.srp全部去掉

11
note/script.txt Normal file
View File

@ -0,0 +1,11 @@
script
06 00 50 00 14 00 头 <-检验
record_count 4B int RAW
[ Data, 数量↑
chunk_size 2B ushort RAW(解密时值-4用)
unknown 4B x RAW
chunk *B byte[] Encrypt(解密需RotByteR 4)
]