- [Core] Added new entries.

This commit is contained in:
Razmoth
2023-12-30 14:38:43 +04:00
parent c51c2b81d8
commit 6cdcc2c292
5 changed files with 103 additions and 16 deletions

View File

@@ -3,10 +3,9 @@ using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace AssetStudio
{
@@ -110,8 +109,7 @@ namespace AssetStudio
private List<StorageBlock> m_BlocksInfo;
public List<StreamFile> fileList;
private bool HasUncompressedDataHash = true;
private bool HasBlockInfoNeedPaddingAtStart = true;
@@ -530,7 +528,15 @@ namespace AssetStudio
}
case CompressionType.Lzma: //LZMA
{
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
var compressedStream = reader.BaseStream;
if (Game.Type.IsNetEase() && i == 0)
{
var compressedBytesSpan = reader.ReadBytes((int)blockInfo.compressedSize).AsSpan();
NetEaseUtils.DecryptWithoutHeader(compressedBytesSpan);
var ms = new MemoryStream(compressedBytesSpan.ToArray());
compressedStream = ms;
}
SevenZipHelper.StreamDecompress(compressedStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
break;
}
case CompressionType.Lz4: //LZ4
@@ -553,7 +559,7 @@ namespace AssetStudio
}
if (Game.Type.IsNetEase() && i == 0)
{
NetEaseUtils.Decrypt(compressedBytesSpan);
NetEaseUtils.DecryptWithHeader(compressedBytesSpan);
}
if (Game.Type.IsArknightsEndfield() && i == 0)
{

View File

@@ -9,29 +9,38 @@ namespace AssetStudio
public static class NetEaseUtils
{
private static readonly byte[] Signature = new byte[] { 0xEE, 0xDD };
public static void Decrypt(Span<byte> bytes)
public static void DecryptWithHeader(Span<byte> bytes)
{
var (encryptedOffset, encryptedSize) = ReadHeader(bytes);
var encrypted = bytes.Slice(encryptedOffset, encryptedSize);
Decrypt(encrypted);
}
public static void DecryptWithoutHeader(Span<byte> bytes)
{
var encrypted = bytes[..Math.Min(bytes.Length, 0x1000)];
Decrypt(encrypted);
}
private static void Decrypt(Span<byte> bytes)
{
Logger.Verbose($"Attempting to decrypt block with NetEase encryption...");
var (encryptedOffset, encryptedSize) = ReadHeader(bytes);
var encrypted = bytes.Slice(encryptedOffset, encryptedSize);
var encryptedInts = MemoryMarshal.Cast<byte, int>(encrypted);
var encryptedInts = MemoryMarshal.Cast<byte, int>(bytes);
var seedInts = new int[] { encryptedInts[3], encryptedInts[1], encryptedInts[4], encrypted.Length, encryptedInts[2] };
var seedInts = new int[] { encryptedInts[3], encryptedInts[1], encryptedInts[4], bytes.Length, encryptedInts[2] };
var seedBytes = MemoryMarshal.AsBytes<int>(seedInts).ToArray();
var seed = (int)CRC.CalculateDigest(seedBytes, 0, (uint)seedBytes.Length);
var keyPart0 = seed ^ (encryptedInts[7] + 0x1981);
var keyPart1 = seed ^ (encrypted.Length + 0x2013);
var keyPart1 = seed ^ (bytes.Length + 0x2013);
var keyPart2 = seed ^ (encryptedInts[5] + 0x1985);
var keyPart3 = seed ^ (encryptedInts[6] + 0x2018);
for (int i = 0; i < 0x20; i++)
{
encrypted[i] ^= 0xA6;
bytes[i] ^= 0xA6;
}
var block = encrypted[0x20..];
var block = bytes[0x20..];
var keyVector = new int[] { keyPart2, keyPart0, keyPart1, keyPart3 };
var keysVector = new int[] { 0x571, keyPart3, 0x892, 0x750, keyPart2, keyPart0, 0x746, keyPart1, 0x568 };
if (block.Length >= 0x80)
@@ -65,7 +74,7 @@ namespace AssetStudio
var remainingCount = dataBlock.Length % 0x80;
if (remainingCount > 0)
{
var remaining = encrypted[^remainingCount..];
var remaining = bytes[^remainingCount..];
for (int i = 0; i < remainingCount; i++)
{
remaining[i] ^= (byte)(keyBlock[i] ^ ((uint)keysVector[(uint)keyVector[i % keyVector.Length] % keysVector.Length] % 0xFF) ^ i);

View File

@@ -212,6 +212,9 @@ namespace AssetStudio
case GameType.Reverse1999:
reader = DecryptReverse1999(reader);
break;
case GameType.JJKPhantomParade:
reader = DecryptReverse1999(reader);
break;
}
}
if (reader.FileType == FileType.BundleFile && game.Type.IsBlockFile() || reader.FileType == FileType.ENCRFile || reader.FileType == FileType.BlbFile)

View File

@@ -43,6 +43,7 @@ namespace AssetStudio
Games.Add(index++, new Game(GameType.GirlsFrontline));
Games.Add(index++, new Game(GameType.Reverse1999));
Games.Add(index++, new Game(GameType.ArknightsEndfield));
Games.Add(index++, new Game(GameType.JJKPhantomParade));
}
public static Game GetGame(GameType gameType) => GetGame((int)gameType);
public static Game GetGame(int index)
@@ -156,7 +157,9 @@ namespace AssetStudio
CodenameJump,
GirlsFrontline,
Reverse1999,
ArknightsEndfield
ArknightsEndfield,
JJKPhantomParade,
}
public static class GameTypes

View File

@@ -950,5 +950,71 @@ namespace AssetStudio
return (byte)(key + (byte)(2 * ((key & 1) + 1)));
}
}
public static FileReader DecryptJJKPhantomParade(FileReader reader)
{
Logger.Verbose($"Attempting to decrypt file {reader.FileName} with Jujutsu Kaisen: Phantom Parade encryption");
var key = reader.ReadBytes(2);
var signatureBytes = reader.ReadBytes(13);
var generation = reader.ReadByte();
for (int i = 0; i < 13; i++)
{
signatureBytes[i] ^= key[i % key.Length];
}
var signature = Encoding.UTF8.GetString(signatureBytes);
if (signature != "_GhostAssets_")
{
throw new Exception("Invalid signature");
}
generation ^= (byte)(key[0] ^ key[1]);
if (generation != 1)
{
throw new Exception("Invalid generation");
}
long value = 0;
var data = reader.ReadBytes((int)reader.Remaining);
var blockCount = data.Length / 0x10;
using var writerMS = new MemoryStream();
using var writer = new BinaryWriter(writerMS);
for (int i = 0; i <= blockCount; i++)
{
if (i % 0x40 == 0)
{
value = 0x64 * ((i / 0x40) + 1);
}
writer.Write(value);
writer.Write((long)0);
value += 1;
}
using var aes = Aes.Create();
aes.Key = new byte[] { 0x36, 0x31, 0x35, 0x34, 0x65, 0x30, 0x30, 0x66, 0x39, 0x45, 0x39, 0x63, 0x65, 0x34, 0x36, 0x64, 0x63, 0x39, 0x30, 0x35, 0x34, 0x45, 0x30, 0x37, 0x31, 0x37, 0x33, 0x41, 0x61, 0x35, 0x34, 0x36 };
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
var encryptor = aes.CreateEncryptor();
var keyBytes = writerMS.ToArray();
keyBytes = encryptor.TransformFinalBlock(keyBytes, 0, keyBytes.Length);
for (int i = 0; i < data.Length; i++)
{
data[i] ^= keyBytes[i];
}
Logger.Verbose("Decrypted Jujutsu Kaisen: Phantom Parade file successfully !!");
MemoryStream ms = new();
ms.Write(data);
ms.Position = 0;
return new FileReader(reader.FullPath, ms);
}
}
}