This commit is contained in:
Razmoth
2023-08-21 21:45:57 +04:00
parent 6da2387c8c
commit 0bd3fa6db2
48 changed files with 967 additions and 510 deletions

View File

@@ -1,5 +1,7 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Text;
namespace AssetStudio
{
@@ -8,16 +10,20 @@ namespace AssetStudio
private const int DataOffset = 0x2A;
private const int KeySize = 0x1000;
private const int SeedBlockSize = 0x800;
private const int BufferSize = 0x10000;
public static XORStream Decrypt(FileReader reader, Blk blk)
{
reader.Endian = EndianType.LittleEndian;
var signature = reader.ReadStringToNull();
Logger.Verbose($"Signature: {signature}");
var count = reader.ReadInt32();
Logger.Verbose($"Key size: {count}");
var key = reader.ReadBytes(count);
reader.Position += count;
var seedSize = Math.Min(reader.ReadInt16(), blk.SBox.IsNullOrEmpty() ? SeedBlockSize : SeedBlockSize * 2);
Logger.Verbose($"Seed size: 0x{seedSize:X8}");
if (!blk.SBox.IsNullOrEmpty() && blk.Type.IsGI())
{
@@ -47,6 +53,8 @@ namespace AssetStudio
var keyHigh = BinaryPrimitives.ReadUInt64LittleEndian(key.AsSpan(8, 8));
var seed = keyLow ^ keyHigh ^ keySeed ^ blk.InitSeed;
Logger.Verbose($"Seed: 0x{seed:X8}");
var mt64 = new MT19937_64(seed);
var xorpad = new byte[KeySize];
for (int i = 0; i < KeySize; i += 8)
@@ -56,5 +64,48 @@ namespace AssetStudio
return new XORStream(reader.BaseStream, DataOffset, xorpad);
}
public static IEnumerable<long> GetOffsets(this XORStream stream, string path)
{
if (AssetsHelper.TryGet(path, out var offsets))
{
foreach(var offset in offsets)
{
stream.Offset = offset;
yield return offset;
}
}
else
{
using var reader = new FileReader(path, stream, true);
var signature = reader.FileType switch
{
FileType.BundleFile => "UnityFS\x00",
FileType.Mhy0File => "mhy0",
_ => throw new InvalidOperationException()
};
Logger.Verbose($"Prased signature: {signature}");
var signatureBytes = Encoding.UTF8.GetBytes(signature);
var buffer = BigArrayPool<byte>.Shared.Rent(BufferSize);
while (stream.Remaining > 0)
{
var index = 0;
var absOffset = stream.AbsolutePosition;
var read = stream.Read(buffer);
while (index < read)
{
index = buffer.AsSpan(0, read).Search(signatureBytes, index);
if (index == -1) break;
var offset = absOffset + index;
stream.Offset = offset;
yield return offset;
index++;
}
}
BigArrayPool<byte>.Shared.Return(buffer);
}
}
}
}

View File

@@ -21,6 +21,7 @@ namespace AssetStudio
var encryptedBlockSize = Math.Min(0x10 * ((data.Length - 0x94) >> 7), BlockSize);
Logger.Verbose($"Encrypted block size: {encryptedBlockSize}");
if (!mr0k.InitVector.IsNullOrEmpty())
{
for (int i = 0; i < mr0k.InitVector.Length; i++)
@@ -47,6 +48,8 @@ namespace AssetStudio
var seed2 = BinaryPrimitives.ReadUInt64LittleEndian(key3);
var seed = seed2 ^ seed1 ^ (seed1 + (uint)data.Length - 20);
Logger.Verbose($"Seed: 0x{seed:X8}");
var encryptedBlock = data.Slice(0x94, encryptedBlockSize);
var seedSpan = BitConverter.GetBytes(seed);
for (var i = 0; i < encryptedBlockSize; i++)

View File

@@ -11,6 +11,8 @@ namespace AssetStudio
private static readonly byte[] Signature = new byte[] { 0xEE, 0xDD };
public 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);
@@ -77,7 +79,7 @@ namespace AssetStudio
}
private static (int, int) ReadHeader(Span<byte> bytes)
{
var index = bytes.Search(Signature, 0);
var index = bytes.Search(Signature);
if (index == -1 || index >= 0x40)
{
throw new Exception("Header not found !!");
@@ -127,6 +129,7 @@ namespace AssetStudio
throw new Exception("Unsupported version");
}
var versionString = version.ToString("X4");
Logger.Verbose($"Bundle version: {versionString}");
Encoding.UTF8.GetBytes(versionString, bytes);
}

View File

@@ -12,6 +12,7 @@ namespace AssetStudio
public static void Decrypt(Span<byte> data, string path)
{
Logger.Verbose($"Attempting to decrypt block with OPFP encryption...");
if (IsEncryptionBundle(path, out var key, out var version))
{
switch (version)
@@ -41,30 +42,39 @@ namespace AssetStudio
{
if (V1_Prefixes.Any(prefix => relativePath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
{
Logger.Verbose("Path matches with V1 prefixes, generatring key...");
key = (byte)Path.GetFileName(relativePath).Length;
version = 1;
Logger.Verbose($"version: {version}, key: {key}");
return true;
}
else if (V0_Prefixes.Any(prefix => relativePath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
{
Logger.Verbose("Path matches with V2 prefixes, generatring key...");
key = (byte)relativePath.Length;
version = 0;
Logger.Verbose($"version: {version}, key: {key}");
return true;
}
}
Logger.Verbose($"Unknown encryption type");
key = 0x00;
version = 0;
return false;
}
private static bool IsFixedPath(string path, out string fixedPath)
{
Logger.Verbose($"Fixing path before checking...");
var dirs = path.Split(Path.DirectorySeparatorChar);
if (dirs.Contains(BaseFolder))
{
var idx = Array.IndexOf(dirs, BaseFolder);
Logger.Verbose($"Seperator found at index {idx}");
fixedPath = string.Join(Path.DirectorySeparatorChar, dirs[(idx+1)..]).Replace("\\", "/");
return true;
}
Logger.Verbose($"Unknown path");
fixedPath = string.Empty;
return false;
}

View File

@@ -28,8 +28,11 @@ namespace AssetStudio
DecryptKey(signatureKey, signatureBytes);
var str = Encoding.UTF8.GetString(signatureBytes);
Logger.Verbose($"Decrypted signature is {str}");
if (str != Signature)
throw new Exception("Invalid Signature !!");
{
throw new Exception($"Invalid Signature, Expected {Signature} but found {str} instead");
}
DecryptKey(infoKey, infoBytes);
@@ -41,19 +44,20 @@ namespace AssetStudio
var idx = (i % 4 * 4) + (i / 4);
Sub[idx] = subBytes[i];
}
}
public static bool SetKey(Entry entry)
{
Logger.Verbose($"Initializing decryptor with key {entry.Key}");
try
{
using (var aes = Aes.Create())
{
aes.Mode = CipherMode.ECB;
aes.Key = Convert.FromHexString(entry.Key);
using var aes = Aes.Create();
aes.Mode = CipherMode.ECB;
aes.Key = Convert.FromHexString(entry.Key);
Encryptor = aes.CreateEncryptor();
}
Encryptor = aes.CreateEncryptor();
Logger.Verbose($"Decryptor initialized !!");
}
catch (Exception e)
{