Skip to content
This repository has been archived by the owner on May 11, 2024. It is now read-only.

Commit

Permalink
- [Core] Added new entries.
Browse files Browse the repository at this point in the history
  • Loading branch information
Razmoth committed Dec 30, 2023
1 parent c51c2b8 commit 6cdcc2c
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 16 deletions.
18 changes: 12 additions & 6 deletions AssetStudio/BundleFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
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
{
Expand Down Expand Up @@ -110,8 +109,7 @@ public override string ToString()
private List<StorageBlock> m_BlocksInfo;

public List<StreamFile> fileList;



private bool HasUncompressedDataHash = true;
private bool HasBlockInfoNeedPaddingAtStart = true;

Expand Down Expand Up @@ -530,7 +528,15 @@ private void ReadBlocks(FileReader reader, Stream blocksStream)
}
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
Expand All @@ -553,7 +559,7 @@ private void ReadBlocks(FileReader reader, Stream blocksStream)
}
if (Game.Type.IsNetEase() && i == 0)
{
NetEaseUtils.Decrypt(compressedBytesSpan);
NetEaseUtils.DecryptWithHeader(compressedBytesSpan);
}
if (Game.Type.IsArknightsEndfield() && i == 0)
{
Expand Down
27 changes: 18 additions & 9 deletions AssetStudio/Crypto/NetEaseUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
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);
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 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)
Expand Down Expand Up @@ -65,7 +74,7 @@ public static void Decrypt(Span<byte> bytes)
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);
Expand Down
3 changes: 3 additions & 0 deletions AssetStudio/FileReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ public static FileReader PreProcessing(this FileReader reader, Game game)
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)
Expand Down
5 changes: 4 additions & 1 deletion AssetStudio/GameManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static GameManager()
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)
Expand Down Expand Up @@ -156,7 +157,9 @@ public enum GameType
CodenameJump,
GirlsFrontline,
Reverse1999,
ArknightsEndfield
ArknightsEndfield,
JJKPhantomParade,

}

public static class GameTypes
Expand Down
66 changes: 66 additions & 0 deletions AssetStudio/ImportHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -950,5 +950,71 @@ static byte GetAbEncryptKey(string md5Name)
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);
}
}
}

0 comments on commit 6cdcc2c

Please sign in to comment.