mirror of
https://github.com/rvtr/ctr_test_tools.git
synced 2025-06-19 09:05:31 -04:00
TwlBkpCheck/Windows:ヘッダ情報の更新(今までのは Legacy としてクラス分け)
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_test_tools@27 6b0af911-cb57-b745-895f-eec5701120e1
This commit is contained in:
parent
82f3c9c94c
commit
f26671db85
@ -49,6 +49,7 @@ namespace FalsifyTwlBackup
|
|||||||
private const int CAT300 = 3;
|
private const int CAT300 = 3;
|
||||||
private const int CAT400 = 4;
|
private const int CAT400 = 4;
|
||||||
private const int CAT500 = 5;
|
private const int CAT500 = 5;
|
||||||
|
private const int VERIFY = 9; // TORIAEZU : 上記が Mode == Pattern なのが引っかかる・・・
|
||||||
|
|
||||||
// 各カテゴリでの最大番号
|
// 各カテゴリでの最大番号
|
||||||
private const int MAX_OF_CAT100 = 118;
|
private const int MAX_OF_CAT100 = 118;
|
||||||
@ -92,6 +93,7 @@ namespace FalsifyTwlBackup
|
|||||||
Console.WriteLine(" ex) -cat 100 -> falsifying 100,101,102....");
|
Console.WriteLine(" ex) -cat 100 -> falsifying 100,101,102....");
|
||||||
Console.WriteLine(" -each PAT_NUM : output PAT_NUM pattern");
|
Console.WriteLine(" -each PAT_NUM : output PAT_NUM pattern");
|
||||||
Console.WriteLine(" ex) -each 204 -> falsifying 204 only");
|
Console.WriteLine(" ex) -each 204 -> falsifying 204 only");
|
||||||
|
Console.WriteLine(" -verify : verify backup file");
|
||||||
Environment.Exit(-1);
|
Environment.Exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +180,14 @@ namespace FalsifyTwlBackup
|
|||||||
return Convert.ToInt16(args[4]);
|
return Convert.ToInt16(args[4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -verify
|
||||||
|
else if (args[3].ToUpper().TrimStart('-') == "VERIFY")
|
||||||
|
{
|
||||||
|
return VERIFY;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// それ以外
|
// それ以外
|
||||||
return ALL;
|
return ALL;
|
||||||
}
|
}
|
||||||
@ -265,12 +274,24 @@ namespace FalsifyTwlBackup
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case INDEX_TMD:
|
case INDEX_TMD:
|
||||||
case INDEX_CONTENT:
|
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.TMD], 0);
|
||||||
case INDEX_PUBLIC_SAVE:
|
|
||||||
case INDEX_SUB_BANNER:
|
|
||||||
hash.CopyTo(signature.digest.section[index - (INDEX_SIGNATURE + 1)], 0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// TODO : マルチコンテンツ対応
|
||||||
|
case INDEX_CONTENT:
|
||||||
|
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.CONTENT], 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INDEX_PUBLIC_SAVE:
|
||||||
|
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.PUBLIC_SAVE], 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INDEX_SUB_BANNER:
|
||||||
|
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.SUB_BANNER], 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TODO : Private Save 追加
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Debug.Assert(false);
|
Debug.Assert(false);
|
||||||
break;
|
break;
|
||||||
@ -286,38 +307,6 @@ namespace FalsifyTwlBackup
|
|||||||
/// <returns>連結後のbyte列</returns>
|
/// <returns>連結後のbyte列</returns>
|
||||||
static byte[] MergeByteArray(byte[] front, byte[] rear)
|
static byte[] MergeByteArray(byte[] front, byte[] rear)
|
||||||
{
|
{
|
||||||
/* 私のコード(色々アレだよ;;)
|
|
||||||
byte[] merged = new byte[front.Length + rear.Length];
|
|
||||||
for (int i = 0; i < (front.Length + rear.Length); i++)
|
|
||||||
{
|
|
||||||
if (i < front.Length)
|
|
||||||
{
|
|
||||||
merged[i] = front[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
merged[i] = rear[i - front.Length];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* 田中さん案1(中にifは使わないほうがいいよ)
|
|
||||||
for (int i = 0; i < front.Length; i++)
|
|
||||||
{
|
|
||||||
merged[i] = front[i];
|
|
||||||
}
|
|
||||||
for (int i = 0; i < rear.Length; i++)
|
|
||||||
{
|
|
||||||
merged[i + front.Length] = rear[i];
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* 田中さん案2(ライブラリを使うとコピーしてるのも分かりやすいよ^^)
|
|
||||||
Array.Copy(front, 0, merged, 0, front.Length);
|
|
||||||
Array.Copy(rear, 0, merged, front.Length, rear.Length);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 田中さん案3(結局1行で出来ちゃったよ;;)
|
|
||||||
return front.Concat(rear).ToArray();
|
return front.Concat(rear).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +384,7 @@ namespace FalsifyTwlBackup
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 各ブロックを暗号化した後、1つのbute列に結合します。
|
/// 各ブロックを暗号化した後、1つの byte 列に結合します。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dataBlocks">暗号化するデータ</param>
|
/// <param name="dataBlocks">暗号化するデータ</param>
|
||||||
/// <param name="prop">バックアップデータに関するインスタンス</param>
|
/// <param name="prop">バックアップデータに関するインスタンス</param>
|
||||||
@ -662,7 +651,10 @@ namespace FalsifyTwlBackup
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 211:
|
case 211:
|
||||||
header.contentId++;
|
for (int i = 0; i < header.contentId.Length; i++)
|
||||||
|
{
|
||||||
|
header.contentId[i]++;
|
||||||
|
}
|
||||||
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
|
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
|
||||||
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
|
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
|
||||||
break;
|
break;
|
||||||
@ -1072,7 +1064,6 @@ namespace FalsifyTwlBackup
|
|||||||
|
|
||||||
Properties prop = new Properties(); // インスタンスの作成
|
Properties prop = new Properties(); // インスタンスの作成
|
||||||
byte[] twlBackupData = File.ReadAllBytes(twlBackupName); // バックアップデータの読み込み
|
byte[] twlBackupData = File.ReadAllBytes(twlBackupName); // バックアップデータの読み込み
|
||||||
prop.SetOutputFolderPath(twlBackupName); // 出力フォルダを作成
|
|
||||||
|
|
||||||
// 鍵データの読み込み
|
// 鍵データの読み込み
|
||||||
string[] keyString = File.ReadAllLines(keyName);
|
string[] keyString = File.ReadAllLines(keyName);
|
||||||
@ -1092,14 +1083,25 @@ namespace FalsifyTwlBackup
|
|||||||
|
|
||||||
// ファイル名の出力 + 鍵データの dump
|
// ファイル名の出力 + 鍵データの dump
|
||||||
Console.WriteLine("Twl Backup File : {0}", twlBackupName);
|
Console.WriteLine("Twl Backup File : {0}", twlBackupName);
|
||||||
Console.Write("Block Key File : {0}, ", keyName);
|
Console.WriteLine("Block Key File : {0} ({1})", keyName, dumpArray(prop.keyData));
|
||||||
dumpArray("", prop.keyData);
|
Console.WriteLine("MAC Key File : {0} ({1})", macKeyData, dumpArray(prop.macKeyData));
|
||||||
Console.Write("MAC Key Data : {0}, ", macKeyData);
|
|
||||||
dumpArray("", prop.macKeyData);
|
// TORIAEZU : ひとまず VERIFY だったら検証して終了
|
||||||
|
if (falsifyingType == VERIFY)
|
||||||
|
{
|
||||||
|
if (Utility.Verify(twlBackupData, prop.keyData, prop.macKeyData))
|
||||||
|
{
|
||||||
|
Console.WriteLine("{0} は検証に成功しました。", twlBackupName);
|
||||||
|
}
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
// バックアップデータを復号化
|
// バックアップデータを復号化
|
||||||
prop.decryptedBlocks = Utility.DecryptBackupData(twlBackupData, prop.keyData);
|
prop.decryptedBlocks = Utility.DecryptBackupData(twlBackupData, prop.keyData);
|
||||||
|
|
||||||
|
// 出力フォルダを作成
|
||||||
|
prop.SetOutputFolderPath(twlBackupName);
|
||||||
|
|
||||||
//==========================================
|
//==========================================
|
||||||
// 改ざん&ファイル出力
|
// 改ざん&ファイル出力
|
||||||
Console.WriteLine("Start ------------");
|
Console.WriteLine("Start ------------");
|
||||||
@ -1111,14 +1113,14 @@ namespace FalsifyTwlBackup
|
|||||||
}
|
}
|
||||||
|
|
||||||
// byte 配列の 16 進表示
|
// byte 配列の 16 進表示
|
||||||
static void dumpArray(String msg, byte[] array)
|
static string dumpArray(byte[] array)
|
||||||
{
|
{
|
||||||
Console.Write(msg);
|
string str = "";
|
||||||
foreach (byte b in array)
|
foreach (byte b in array)
|
||||||
{
|
{
|
||||||
Console.Write(String.Format("{0,0:X2} ", b));
|
str += String.Format("{0,0:X2} ", b);
|
||||||
}
|
}
|
||||||
Console.WriteLine();
|
return str.TrimEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -43,7 +43,7 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="FalsifyTwlBackup.cs" />
|
||||||
<Compile Include="Properties.cs" />
|
<Compile Include="Properties.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -123,6 +123,18 @@ namespace TwlBackupBlock
|
|||||||
br.Read(buffer, 0, buffer.Length);
|
br.Read(buffer, 0, buffer.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 現在のストリームから指定した配列に2バイト符号なし整数を読み取り、ストリームの現在位置を指定した配列のバイト数だけ進めます。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">データを読み取るバッファ</param>
|
||||||
|
public void Read(UInt16[] buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < buffer.Length; i++)
|
||||||
|
{
|
||||||
|
Read(ref buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 現在のストリームから指定した配列に4バイト符号なし整数を読み取り、ストリームの現在位置を指定した配列のバイト数だけ進めます。
|
/// 現在のストリームから指定した配列に4バイト符号なし整数を読み取り、ストリームの現在位置を指定した配列のバイト数だけ進めます。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,13 +9,14 @@ namespace TwlBackupBlock
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class HeaderBody : AbstractBody
|
public class HeaderBody : AbstractBody
|
||||||
{
|
{
|
||||||
public const int HEADER_SIZE = 160;
|
public const int HEADER_SIZE = 240;
|
||||||
|
|
||||||
public const int UNIQUE_ID_SIZE = 32;
|
public const int UNIQUE_ID_SIZE = 32;
|
||||||
public const int HARDWARE_ID_SIZE = 16;
|
public const int HARDWARE_ID_SIZE = 16;
|
||||||
public const int NUM_OF_SECTION = 4;
|
public const int MAX_CONTENTS = 8;
|
||||||
|
public const int NUM_OF_SECTION = 11;
|
||||||
public const int TMD_RESERVED_SIZE = 62;
|
public const int TMD_RESERVED_SIZE = 62;
|
||||||
public const int RESERVED_SIZE = 4;
|
public const int RESERVED_SIZE = 13;
|
||||||
|
|
||||||
public UInt32 signature;
|
public UInt32 signature;
|
||||||
public UInt16 companyCode;
|
public UInt16 companyCode;
|
||||||
@ -25,9 +26,10 @@ namespace TwlBackupBlock
|
|||||||
public UInt64 titleId;
|
public UInt64 titleId;
|
||||||
public Int64 requiredSize;
|
public Int64 requiredSize;
|
||||||
public readonly UInt32[] fileSizes;
|
public readonly UInt32[] fileSizes;
|
||||||
public UInt32 contentId;
|
public readonly UInt32[] contentId;
|
||||||
|
public readonly UInt16[] contentIndex;
|
||||||
public readonly TmdReserved tmdReserved;
|
public readonly TmdReserved tmdReserved;
|
||||||
public UInt16 contentIndex;
|
public Byte headerVersion;
|
||||||
public readonly Byte[] reserved;
|
public readonly Byte[] reserved;
|
||||||
|
|
||||||
public HeaderBody(byte[] data)
|
public HeaderBody(byte[] data)
|
||||||
@ -45,6 +47,8 @@ namespace TwlBackupBlock
|
|||||||
uniqueId = new Byte[UNIQUE_ID_SIZE];
|
uniqueId = new Byte[UNIQUE_ID_SIZE];
|
||||||
hardwareId = new Byte[HARDWARE_ID_SIZE];
|
hardwareId = new Byte[HARDWARE_ID_SIZE];
|
||||||
fileSizes = new UInt32[NUM_OF_SECTION];
|
fileSizes = new UInt32[NUM_OF_SECTION];
|
||||||
|
contentId = new UInt32[MAX_CONTENTS];
|
||||||
|
contentIndex = new UInt16[MAX_CONTENTS];
|
||||||
tmdReserved = new TmdReserved();
|
tmdReserved = new TmdReserved();
|
||||||
reserved = new Byte[RESERVED_SIZE];
|
reserved = new Byte[RESERVED_SIZE];
|
||||||
|
|
||||||
@ -130,9 +134,16 @@ namespace TwlBackupBlock
|
|||||||
{
|
{
|
||||||
bw.Write(e);
|
bw.Write(e);
|
||||||
}
|
}
|
||||||
bw.Write(contentId);
|
foreach (UInt32 e in contentId)
|
||||||
|
{
|
||||||
|
bw.Write(e);
|
||||||
|
}
|
||||||
|
foreach (UInt16 e in contentIndex)
|
||||||
|
{
|
||||||
|
bw.Write(e);
|
||||||
|
}
|
||||||
bw.Write(tmdReserved.GetBytes());
|
bw.Write(tmdReserved.GetBytes());
|
||||||
bw.Write(contentIndex);
|
bw.Write(headerVersion);
|
||||||
bw.Write(reserved);
|
bw.Write(reserved);
|
||||||
|
|
||||||
Debug.Assert(ms.Position == HEADER_SIZE);
|
Debug.Assert(ms.Position == HEADER_SIZE);
|
||||||
@ -164,13 +175,14 @@ namespace TwlBackupBlock
|
|||||||
br.Read(ref titleId);
|
br.Read(ref titleId);
|
||||||
br.Read(ref requiredSize);
|
br.Read(ref requiredSize);
|
||||||
br.Read(fileSizes);
|
br.Read(fileSizes);
|
||||||
br.Read(ref contentId);
|
br.Read(contentId);
|
||||||
|
br.Read(contentIndex);
|
||||||
{
|
{
|
||||||
byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE];
|
byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE];
|
||||||
br.Read(tmdReservedBytes);
|
br.Read(tmdReservedBytes);
|
||||||
tmdReserved.SetBytes(tmdReservedBytes);
|
tmdReserved.SetBytes(tmdReservedBytes);
|
||||||
}
|
}
|
||||||
br.Read(ref contentIndex);
|
br.Read(ref headerVersion);
|
||||||
br.Read(reserved);
|
br.Read(reserved);
|
||||||
|
|
||||||
Debug.Assert(ms.Position == HEADER_SIZE);
|
Debug.Assert(ms.Position == HEADER_SIZE);
|
||||||
@ -182,79 +194,4 @@ namespace TwlBackupBlock
|
|||||||
return new HeaderBody(GetBytes());
|
return new HeaderBody(GetBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ヘッダブロック中のTMDReserved。
|
|
||||||
/// </summary>
|
|
||||||
public class TmdReserved
|
|
||||||
{
|
|
||||||
private const int TMD_RESERVED_SIZE = 62;
|
|
||||||
|
|
||||||
public const int RESERVED8_SIZE = 3;
|
|
||||||
public const int PARENTAL_CONTROL_SIZE = 16;
|
|
||||||
public const int RESERVED_SIZE = 30;
|
|
||||||
|
|
||||||
public UInt32 publicSaveSize;
|
|
||||||
public UInt32 privateSaveSize;
|
|
||||||
public UInt32 reserved32;
|
|
||||||
public Byte flags;
|
|
||||||
public readonly Byte[] reserved8;
|
|
||||||
public readonly Byte[] parentalControl;
|
|
||||||
public readonly Byte[] reserved;
|
|
||||||
|
|
||||||
public TmdReserved()
|
|
||||||
{
|
|
||||||
reserved8 = new Byte[RESERVED8_SIZE];
|
|
||||||
parentalControl = new Byte[PARENTAL_CONTROL_SIZE];
|
|
||||||
reserved = new Byte[RESERVED_SIZE];
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] GetBytes()
|
|
||||||
{
|
|
||||||
byte[] bytes = new byte[TMD_RESERVED_SIZE];
|
|
||||||
|
|
||||||
using (var ms = new MemoryStream(bytes))
|
|
||||||
using (var bw = new BinaryWriter(ms))
|
|
||||||
{
|
|
||||||
bw.Write(publicSaveSize);
|
|
||||||
bw.Write(privateSaveSize);
|
|
||||||
bw.Write(reserved32);
|
|
||||||
bw.Write(flags);
|
|
||||||
bw.Write(reserved8);
|
|
||||||
bw.Write(parentalControl);
|
|
||||||
bw.Write(reserved);
|
|
||||||
|
|
||||||
Debug.Assert(ms.Position == TMD_RESERVED_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetBytes(byte[] bytes)
|
|
||||||
{
|
|
||||||
if (bytes == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("bytes");
|
|
||||||
}
|
|
||||||
if (bytes.Length != TMD_RESERVED_SIZE)
|
|
||||||
{
|
|
||||||
string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", TMD_RESERVED_SIZE, bytes.Length);
|
|
||||||
throw new ArgumentException("bytes", message);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var ms = new MemoryStream(bytes))
|
|
||||||
using (var br = new ExtBinaryReader(ms))
|
|
||||||
{
|
|
||||||
br.Read(ref publicSaveSize);
|
|
||||||
br.Read(ref privateSaveSize);
|
|
||||||
br.Read(ref reserved32);
|
|
||||||
br.Read(ref flags);
|
|
||||||
br.Read(reserved8);
|
|
||||||
br.Read(parentalControl);
|
|
||||||
br.Read(reserved);
|
|
||||||
|
|
||||||
Debug.Assert(ms.Position == TMD_RESERVED_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
185
TwlBkpCheck/Windows/TWLBackupBlock/LegacyHeaderBody.cs
Normal file
185
TwlBkpCheck/Windows/TWLBackupBlock/LegacyHeaderBody.cs
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace TwlBackupBlock
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ヘッダブロックのデータ本体。
|
||||||
|
/// </summary>
|
||||||
|
public class LegacyHeaderBody : AbstractBody
|
||||||
|
{
|
||||||
|
public const int HEADER_SIZE = 160;
|
||||||
|
|
||||||
|
public const int UNIQUE_ID_SIZE = 32;
|
||||||
|
public const int HARDWARE_ID_SIZE = 16;
|
||||||
|
public const int NUM_OF_SECTION = 4;
|
||||||
|
public const int TMD_RESERVED_SIZE = 62;
|
||||||
|
public const int RESERVED_SIZE = 4;
|
||||||
|
|
||||||
|
public UInt32 signature;
|
||||||
|
public UInt16 companyCode;
|
||||||
|
public UInt16 version;
|
||||||
|
public readonly Byte[] uniqueId;
|
||||||
|
public readonly Byte[] hardwareId;
|
||||||
|
public UInt64 titleId;
|
||||||
|
public Int64 requiredSize;
|
||||||
|
public readonly UInt32[] fileSizes;
|
||||||
|
public UInt32 contentId;
|
||||||
|
public readonly TmdReserved tmdReserved;
|
||||||
|
public UInt16 contentIndex;
|
||||||
|
public readonly Byte[] reserved;
|
||||||
|
|
||||||
|
public LegacyHeaderBody(byte[] data)
|
||||||
|
{
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("data");
|
||||||
|
}
|
||||||
|
if (data.Length != HEADER_SIZE)
|
||||||
|
{
|
||||||
|
string message = string.Format("data.Length % {0} != 0 (data.Length:{1})", HEADER_SIZE, data.Length);
|
||||||
|
throw new ArgumentException("data", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueId = new Byte[UNIQUE_ID_SIZE];
|
||||||
|
hardwareId = new Byte[HARDWARE_ID_SIZE];
|
||||||
|
fileSizes = new UInt32[NUM_OF_SECTION];
|
||||||
|
tmdReserved = new TmdReserved();
|
||||||
|
reserved = new Byte[RESERVED_SIZE];
|
||||||
|
|
||||||
|
SetBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= HEADER_SIZE)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("index");
|
||||||
|
}
|
||||||
|
return ReadByte(index);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= HEADER_SIZE)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("index");
|
||||||
|
}
|
||||||
|
WriteByte(index, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Length
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return HEADER_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定したバイトを取得します。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">取得したいバイトのインデックス。</param>
|
||||||
|
/// <returns><paramref name="index"/>で指定したバイト</returns>
|
||||||
|
public byte ReadByte(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= HEADER_SIZE)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("index");
|
||||||
|
}
|
||||||
|
// TODO 処理が遅ければ効率化
|
||||||
|
byte[] bytes = GetBytes();
|
||||||
|
return bytes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定したバイトを書き換えます。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">書き換えたいバイトのインデックス。</param>
|
||||||
|
/// <param name="b">上書きに使うバイト。</param>
|
||||||
|
public void WriteByte(int index, byte b)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= HEADER_SIZE)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("index");
|
||||||
|
}
|
||||||
|
// TODO 処理が遅ければ効率化
|
||||||
|
byte[] bytes = GetBytes();
|
||||||
|
bytes[index] = b;
|
||||||
|
SetBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte[] GetBytes()
|
||||||
|
{
|
||||||
|
byte[] bytes = new byte[HEADER_SIZE];
|
||||||
|
|
||||||
|
using (var ms = new MemoryStream(bytes))
|
||||||
|
using (var bw = new BinaryWriter(ms))
|
||||||
|
{
|
||||||
|
bw.Write(signature);
|
||||||
|
bw.Write(companyCode);
|
||||||
|
bw.Write(version);
|
||||||
|
bw.Write(uniqueId);
|
||||||
|
bw.Write(hardwareId);
|
||||||
|
bw.Write(titleId);
|
||||||
|
bw.Write(requiredSize);
|
||||||
|
foreach (UInt32 e in fileSizes)
|
||||||
|
{
|
||||||
|
bw.Write(e);
|
||||||
|
}
|
||||||
|
bw.Write(contentId);
|
||||||
|
bw.Write(tmdReserved.GetBytes());
|
||||||
|
bw.Write(contentIndex);
|
||||||
|
bw.Write(reserved);
|
||||||
|
|
||||||
|
Debug.Assert(ms.Position == HEADER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("bytes");
|
||||||
|
}
|
||||||
|
if (bytes.Length != HEADER_SIZE)
|
||||||
|
{
|
||||||
|
string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", HEADER_SIZE, bytes.Length);
|
||||||
|
throw new ArgumentException("bytes", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var ms = new MemoryStream(bytes))
|
||||||
|
using (var br = new ExtBinaryReader(ms))
|
||||||
|
{
|
||||||
|
br.Read(ref signature);
|
||||||
|
br.Read(ref companyCode);
|
||||||
|
br.Read(ref version);
|
||||||
|
br.Read(uniqueId);
|
||||||
|
br.Read(hardwareId);
|
||||||
|
br.Read(ref titleId);
|
||||||
|
br.Read(ref requiredSize);
|
||||||
|
br.Read(fileSizes);
|
||||||
|
br.Read(ref contentId);
|
||||||
|
{
|
||||||
|
byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE];
|
||||||
|
br.Read(tmdReservedBytes);
|
||||||
|
tmdReserved.SetBytes(tmdReservedBytes);
|
||||||
|
}
|
||||||
|
br.Read(ref contentIndex);
|
||||||
|
br.Read(reserved);
|
||||||
|
|
||||||
|
Debug.Assert(ms.Position == HEADER_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object Clone()
|
||||||
|
{
|
||||||
|
return new HeaderBody(GetBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,8 @@ namespace TwlBackupBlock
|
|||||||
public class TwlBackupHashSet
|
public class TwlBackupHashSet
|
||||||
{
|
{
|
||||||
public const int HASH_SIZE = 32;
|
public const int HASH_SIZE = 32;
|
||||||
public const int NUM_OF_SECTION = 4;
|
public const int NUM_OF_SECTION = 11;
|
||||||
|
public const int NUM_OF_LEGACY_SECTION = 4;
|
||||||
|
|
||||||
public readonly byte[] banner;
|
public readonly byte[] banner;
|
||||||
public readonly byte[] header;
|
public readonly byte[] header;
|
||||||
@ -19,11 +20,12 @@ namespace TwlBackupBlock
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// コンストラクタ。
|
/// コンストラクタ。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TwlBackupHashSet()
|
public TwlBackupHashSet(bool isLegacy = false)
|
||||||
{
|
{
|
||||||
banner = new byte[HASH_SIZE];
|
banner = new byte[HASH_SIZE];
|
||||||
header = new byte[HASH_SIZE];
|
header = new byte[HASH_SIZE];
|
||||||
section = new byte[NUM_OF_SECTION][];
|
section = isLegacy ?
|
||||||
|
new byte[NUM_OF_LEGACY_SECTION][] : new byte[NUM_OF_SECTION][];
|
||||||
for (int i = 0; i < section.Length; i++)
|
for (int i = 0; i < section.Length; i++)
|
||||||
{
|
{
|
||||||
section[i] = new byte[HASH_SIZE];
|
section[i] = new byte[HASH_SIZE];
|
||||||
@ -35,7 +37,8 @@ namespace TwlBackupBlock
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SignatureBody : AbstractBody
|
public class SignatureBody : AbstractBody
|
||||||
{
|
{
|
||||||
public const int SIGNATURE_SIZE = 1024;
|
public const int SIGNATURE_SIZE = 1248;
|
||||||
|
public const int LEGACY_SIGNATURE_SIZE = 1024;
|
||||||
|
|
||||||
public const int ECC_SIGN_SIZE = 60;
|
public const int ECC_SIGN_SIZE = 60;
|
||||||
public const int ECC_CERT_SIZE = 384;
|
public const int ECC_CERT_SIZE = 384;
|
||||||
|
82
TwlBkpCheck/Windows/TWLBackupBlock/TmdReserved.cs
Normal file
82
TwlBkpCheck/Windows/TWLBackupBlock/TmdReserved.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace TwlBackupBlock
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ヘッダブロック中のTMDReserved。
|
||||||
|
/// Normal, Legacy 共に共通。
|
||||||
|
/// </summary>
|
||||||
|
public class TmdReserved
|
||||||
|
{
|
||||||
|
private const int TMD_RESERVED_SIZE = 62;
|
||||||
|
|
||||||
|
public const int RESERVED8_SIZE = 3;
|
||||||
|
public const int PARENTAL_CONTROL_SIZE = 16;
|
||||||
|
public const int RESERVED_SIZE = 30;
|
||||||
|
|
||||||
|
public UInt32 publicSaveSize;
|
||||||
|
public UInt32 privateSaveSize;
|
||||||
|
public UInt32 reserved32;
|
||||||
|
public Byte flags;
|
||||||
|
public readonly Byte[] reserved8;
|
||||||
|
public readonly Byte[] parentalControl;
|
||||||
|
public readonly Byte[] reserved;
|
||||||
|
|
||||||
|
public TmdReserved()
|
||||||
|
{
|
||||||
|
reserved8 = new Byte[RESERVED8_SIZE];
|
||||||
|
parentalControl = new Byte[PARENTAL_CONTROL_SIZE];
|
||||||
|
reserved = new Byte[RESERVED_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetBytes()
|
||||||
|
{
|
||||||
|
byte[] bytes = new byte[TMD_RESERVED_SIZE];
|
||||||
|
|
||||||
|
using (var ms = new MemoryStream(bytes))
|
||||||
|
using (var bw = new BinaryWriter(ms))
|
||||||
|
{
|
||||||
|
bw.Write(publicSaveSize);
|
||||||
|
bw.Write(privateSaveSize);
|
||||||
|
bw.Write(reserved32);
|
||||||
|
bw.Write(flags);
|
||||||
|
bw.Write(reserved8);
|
||||||
|
bw.Write(parentalControl);
|
||||||
|
bw.Write(reserved);
|
||||||
|
|
||||||
|
Debug.Assert(ms.Position == TMD_RESERVED_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("bytes");
|
||||||
|
}
|
||||||
|
if (bytes.Length != TMD_RESERVED_SIZE)
|
||||||
|
{
|
||||||
|
string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", TMD_RESERVED_SIZE, bytes.Length);
|
||||||
|
throw new ArgumentException("bytes", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var ms = new MemoryStream(bytes))
|
||||||
|
using (var br = new ExtBinaryReader(ms))
|
||||||
|
{
|
||||||
|
br.Read(ref publicSaveSize);
|
||||||
|
br.Read(ref privateSaveSize);
|
||||||
|
br.Read(ref reserved32);
|
||||||
|
br.Read(ref flags);
|
||||||
|
br.Read(reserved8);
|
||||||
|
br.Read(parentalControl);
|
||||||
|
br.Read(reserved);
|
||||||
|
|
||||||
|
Debug.Assert(ms.Position == TMD_RESERVED_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -58,6 +58,7 @@
|
|||||||
<Compile Include="AesCmac.cs" />
|
<Compile Include="AesCmac.cs" />
|
||||||
<Compile Include="Body.cs" />
|
<Compile Include="Body.cs" />
|
||||||
<Compile Include="ExtBinaryReader.cs" />
|
<Compile Include="ExtBinaryReader.cs" />
|
||||||
|
<Compile Include="LegacyHeaderBody.cs" />
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
@ -68,6 +69,7 @@
|
|||||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
<DependentUpon>Settings.settings</DependentUpon>
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="TmdReserved.cs" />
|
||||||
<Compile Include="Utility.cs" />
|
<Compile Include="Utility.cs" />
|
||||||
<Compile Include="AbstractBody.cs" />
|
<Compile Include="AbstractBody.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
@ -13,6 +13,16 @@ namespace TwlBackupBlock
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Utility
|
public class Utility
|
||||||
{
|
{
|
||||||
|
public const int MAX_CONTENTS = 8;
|
||||||
|
public enum SectionIndex
|
||||||
|
{
|
||||||
|
TMD,
|
||||||
|
CONTENT,
|
||||||
|
PUBLIC_SAVE = CONTENT + MAX_CONTENTS,
|
||||||
|
SUB_BANNER,
|
||||||
|
PRIVATE_SAVE
|
||||||
|
};
|
||||||
|
|
||||||
private const int KEY_SIZE = 16;
|
private const int KEY_SIZE = 16;
|
||||||
private const int ROUND_SCALE = 16;
|
private const int ROUND_SCALE = 16;
|
||||||
|
|
||||||
@ -21,8 +31,10 @@ namespace TwlBackupBlock
|
|||||||
private const int AES_SIGN_HEADER_SIZE = 32;
|
private const int AES_SIGN_HEADER_SIZE = 32;
|
||||||
|
|
||||||
private const int BANNER_SIZE = 16 * 1024;
|
private const int BANNER_SIZE = 16 * 1024;
|
||||||
private const int HEADER_SIZE = 160;
|
private const int HEADER_SIZE = 240;
|
||||||
private const int SIGNATURE_SIZE = 1024;
|
private const int SIGNATURE_SIZE = 1248;
|
||||||
|
private const int LEGACY_HEADER_SIZE = 160;
|
||||||
|
private const int LEGACY_SIGNATURE_SIZE = 1024;
|
||||||
|
|
||||||
private const int ENCRYPT_BANNER_SIZE = BANNER_SIZE + AES_SIGN_HEADER_SIZE;
|
private const int ENCRYPT_BANNER_SIZE = BANNER_SIZE + AES_SIGN_HEADER_SIZE;
|
||||||
private const int ENCRYPT_HEADER_SIZE = HEADER_SIZE + AES_SIGN_HEADER_SIZE;
|
private const int ENCRYPT_HEADER_SIZE = HEADER_SIZE + AES_SIGN_HEADER_SIZE;
|
||||||
@ -74,14 +86,16 @@ namespace TwlBackupBlock
|
|||||||
|
|
||||||
blocks.signature.body = new SignatureBody(DecryptBlock(br, SIGNATURE_SIZE, key, out blocks.signature.mac, out blocks.signature.iv));
|
blocks.signature.body = new SignatureBody(DecryptBlock(br, SIGNATURE_SIZE, key, out blocks.signature.mac, out blocks.signature.iv));
|
||||||
|
|
||||||
int TMD_SIZE = (int)headerBody.fileSizes[0];
|
// TORIAEZU
|
||||||
int CONTENT_SIZE = (int)headerBody.fileSizes[1];
|
// TODO : 複数コンテンツ対応
|
||||||
int SAVE_DATA_SIZE = (int)headerBody.fileSizes[2];
|
int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
|
||||||
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[3];
|
int CONTENT_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.CONTENT];
|
||||||
|
int PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.PUBLIC_SAVE];
|
||||||
|
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.SUB_BANNER];
|
||||||
|
|
||||||
blocks.tmd.body = new Body(DecryptBlock(br, TMD_SIZE, key, out blocks.tmd.mac, out blocks.tmd.iv));
|
blocks.tmd.body = new Body(DecryptBlock(br, TMD_SIZE, key, out blocks.tmd.mac, out blocks.tmd.iv));
|
||||||
blocks.content.body = new Body(DecryptBlock(br, CONTENT_SIZE, key, out blocks.content.mac, out blocks.content.iv));
|
blocks.content.body = new Body(DecryptBlock(br, CONTENT_SIZE, key, out blocks.content.mac, out blocks.content.iv));
|
||||||
blocks.saveData.body = new Body(DecryptBlock(br, SAVE_DATA_SIZE, key, out blocks.saveData.mac, out blocks.saveData.iv));
|
blocks.saveData.body = new Body(DecryptBlock(br, PUBLIC_SAVE_SIZE, key, out blocks.saveData.mac, out blocks.saveData.iv));
|
||||||
blocks.subBanner.body = new Body(DecryptBlock(br, SUB_BANNER_SIZE, key, out blocks.subBanner.mac, out blocks.subBanner.iv));
|
blocks.subBanner.body = new Body(DecryptBlock(br, SUB_BANNER_SIZE, key, out blocks.subBanner.mac, out blocks.subBanner.iv));
|
||||||
|
|
||||||
Debug.Assert(ms.Position == data.Length);
|
Debug.Assert(ms.Position == data.Length);
|
||||||
@ -386,13 +400,14 @@ namespace TwlBackupBlock
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TMD_SIZE = (int)headerBody.fileSizes[0];
|
// TODO : 複数コンテンツ対応
|
||||||
int CONTENT_SIZE = (int)headerBody.fileSizes[1];
|
int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
|
||||||
int SAVE_DATA_SIZE = (int)headerBody.fileSizes[2];
|
int CONTENT_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.CONTENT];
|
||||||
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[3];
|
int PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.PUBLIC_SAVE];
|
||||||
|
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.SUB_BANNER];
|
||||||
|
|
||||||
int restSize = RoundUp(TMD_SIZE, ROUND_SCALE) + RoundUp(CONTENT_SIZE, ROUND_SCALE) +
|
int restSize = RoundUp(TMD_SIZE, ROUND_SCALE) + RoundUp(CONTENT_SIZE, ROUND_SCALE) +
|
||||||
RoundUp(SAVE_DATA_SIZE, ROUND_SCALE) + RoundUp(SUB_BANNER_SIZE, ROUND_SCALE) +
|
RoundUp(PUBLIC_SAVE_SIZE, ROUND_SCALE) + RoundUp(SUB_BANNER_SIZE, ROUND_SCALE) +
|
||||||
AES_SIGN_HEADER_SIZE * 4;
|
AES_SIGN_HEADER_SIZE * 4;
|
||||||
if (data.Length - ms.Position != restSize)
|
if (data.Length - ms.Position != restSize)
|
||||||
{
|
{
|
||||||
@ -405,7 +420,7 @@ namespace TwlBackupBlock
|
|||||||
Console.WriteLine("TMDブロックのMACが一致しません");
|
Console.WriteLine("TMDブロックのMACが一致しません");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!CheckHash(blocks.tmd, signatureBody.digest.section[0]))
|
if (!CheckHash(blocks.tmd, signatureBody.digest.section[(int)SectionIndex.TMD]))
|
||||||
{
|
{
|
||||||
Console.WriteLine("TMDブロックのハッシュが一致しません");
|
Console.WriteLine("TMDブロックのハッシュが一致しません");
|
||||||
return false;
|
return false;
|
||||||
@ -416,18 +431,18 @@ namespace TwlBackupBlock
|
|||||||
Console.WriteLine("コンテンツブロックのMACが一致しません");
|
Console.WriteLine("コンテンツブロックのMACが一致しません");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!CheckHash(blocks.content, signatureBody.digest.section[1]))
|
if (!CheckHash(blocks.content, signatureBody.digest.section[(int)SectionIndex.CONTENT]))
|
||||||
{
|
{
|
||||||
Console.WriteLine("コンテンツブロックのハッシュが一致しません");
|
Console.WriteLine("コンテンツブロックのハッシュが一致しません");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
blocks.saveData.body = new Body(DecryptBlock(br, SAVE_DATA_SIZE, aesCbcKey, out blocks.saveData.mac, out blocks.saveData.iv));
|
blocks.saveData.body = new Body(DecryptBlock(br, PUBLIC_SAVE_SIZE, aesCbcKey, out blocks.saveData.mac, out blocks.saveData.iv));
|
||||||
if (!CheckMac(blocks.saveData, aesCmacKey, blocks.saveData.mac))
|
if (!CheckMac(blocks.saveData, aesCmacKey, blocks.saveData.mac))
|
||||||
{
|
{
|
||||||
Console.WriteLine("publicセーブデータブロックのMACが一致しません");
|
Console.WriteLine("publicセーブデータブロックのMACが一致しません");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!CheckHash(blocks.saveData, signatureBody.digest.section[2]))
|
if (!CheckHash(blocks.saveData, signatureBody.digest.section[(int)SectionIndex.PUBLIC_SAVE]))
|
||||||
{
|
{
|
||||||
Console.WriteLine("publicセーブデータブロックのハッシュが一致しません");
|
Console.WriteLine("publicセーブデータブロックのハッシュが一致しません");
|
||||||
return false;
|
return false;
|
||||||
@ -438,7 +453,7 @@ namespace TwlBackupBlock
|
|||||||
Console.WriteLine("サブバナーブロックの内容とMACが一致しません");
|
Console.WriteLine("サブバナーブロックの内容とMACが一致しません");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!CheckHash(blocks.subBanner, signatureBody.digest.section[3]))
|
if (!CheckHash(blocks.subBanner, signatureBody.digest.section[(int)SectionIndex.SUB_BANNER]))
|
||||||
{
|
{
|
||||||
Console.WriteLine("サブバナーブロックのハッシュが一致しません");
|
Console.WriteLine("サブバナーブロックのハッシュが一致しません");
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user