Kuriimu
Kuriimu copied to clipboard
[Plugin request] Decrypt/Encrypt Archive/Text.bin
Issue: Plugin request Console: PC Format extension(s): BIN Filename: textdata.bin Type: ARCHIVE (TEXT?) Game Name: Taishou x Alice Episode I STEAM: https://store.steampowered.com/app/1056570/TAISHO_x_ALICE_episode_1/
First 8 bytes of the file(s): Extension: bin Hex: 95 6B 3C 9D 63 CE B9 0F 95 ASCII: •k<cι•
More details: The file seems encrypted. In the ".7z" you'll find the same file from the japanese, english and spanish version of the game.
I used this https://github.com/jjolano/unpac/releases to unpack "archivee.dat" and obtain "textdata.bin"
Sample files (if possible): https://www.mediafire.com/file/ndld88z69wwpxgy/Textdata.7z/file
If it's rly encrypted the game binary is absolutely needed. So pls add that to your sample files.
Done! The link is the same as before. English and spanish files use the same binary file.
The file was encrypted by a sequential XOR. The initialization value is 0xC5 and with each position this value advances by 0x5C. XOR each byte in the file by this logic and you're golden. Kuriimu2 implements a "Sequential XOR" in its newest dev build and upcomgin Release 1.2.1 to use for this. Use "Key"=C5 and "Step"=5C to make it work.
Translation plan
To start translating this game, you need to take into account that you have to go through two layers.
PAC2 (*.DAT)
The first one is the archive, a format called PAC2 which I solved with the next algorithm:
List<FileObj> fileList = new List<FileObj>();
if (br.ReadInt32() != 0x454d4147 || br.ReadInt32() != 0x20544144 || br.ReadInt32() != 0x32434150) //GAMEDAT PAC2
{
Console.WriteLine("Not supported file, must be a PAC2 format");
Console.ReadLine();
return;
}
int fileCount = br.ReadInt32();
br.BaseStream.Position = 0x10 + 0x20 * fileCount;
for (int i = 0; i < fileCount; i++)
{
fileList.Add(new FileObj()
{
Position = br.ReadInt32() + (0x10 + 0x20 * fileCount) + 0x30,
Size = br.ReadInt32()
});
}
br.BaseStream.Position = 0x10;
for (int i = 0; i < fileCount; i++)
{
fileList[i].FileName = Encoding.ASCII.GetString(br.ReadBytes(0x20)).Replace("\0", "");
}
if (fileList.Count > 0)
{
Directory.CreateDirectory(Path.GetDirectoryName(path) + "\\" + Path.GetFileNameWithoutExtension(path));
for (int i = 0; i < fileList.Count; i++)
{
br.BaseStream.Position = fileList[i].Position;
fileList[i].Stream = br.ReadBytes(fileList[i].Size);
Console.WriteLine("Unpacking... " + fileList[i].FileName);
File.WriteAllBytes(Path.GetDirectoryName(path) + "\\" + Path.GetFileNameWithoutExtension(path) + "\\" + fileList[i].FileName, fileList[i].Stream);
}
Console.WriteLine("Unpacked!");
}
This will dump the archive into a folder, inside, you will find the next files:
- BGM.ini
- filename.dat
- GAME.ini
- graphic.bin
- scenario.dat
- textdata.bin
TEXTDATA.BIN (PJADV_TF)
From all those files, you can find the text in textdata.bin, this file is encrypted using a Sequential XOR algorithm. The Key is 0xC5 and the Step is 0x5C. This algorithm has been implemented in Kuriimu 2 a few days ago by @onepiecefreak3. When you decrypt that, the format is a simple null-terminated SJIS string-poblated file format, just split by ("\0\0") A quick dump would be done by using the next algorithm:
Encoding encoding = Encoding.GetEncoding(932);
List<string> strings = new List<string>();
var fileID = dr.ReadBytes(0x10);
for (int i = 0; i < 0x2cfe; i++)
{
strings.Add(dr.ReadStringToToken("\0\0", encoding));
}
After that, encrypt using the same keys found ahead and pack the data.
Problems found in the process
While the text format is a simple null-terminated string format, the game has hidden pointers in the flow script format found in the file scenario.dat
You need to keep that in mind when you dump the text and when you insert the text since you have to change those pointers.
These are some differences between the Japanese archive and the English one...