using System; using System.Linq; using System.Text; using System.IO; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using TwlBackupBlock; // TODO もっとアサートを入れましょう namespace FalsifyTwlBackup { partial class Program { private const int MAX_CONTENTS = 8; // ブロックセクション private const int SECTION_BANNER = 0; private const int SECTION_HEADER = 1; private const int SECTION_SIGNATURE = 2; private const int SECTION_TMD = 3; private const int SECTION_CONTENT = 4; private const int SECTION_PUBLIC_SAVE = SECTION_CONTENT + MAX_CONTENTS; private const int SECTION_SUB_BANNER = SECTION_PUBLIC_SAVE + 1; private const int SECTION_PRIVATE_SAVE = SECTION_SUB_BANNER + 1; // データの挿入位置 private const int NONE = -1; private const int FRONT_BANNER = 100; // ブロック内データ本体の前 private const int FRONT_HEADER = 101; private const int FRONT_SIGNATURE = 102; private const int FRONT_TMD = 103; private const int FRONT_CONTENT = 104; private const int FRONT_PUBLIC_SAVE = FRONT_CONTENT + MAX_CONTENTS; private const int FRONT_SUB_BANNER = FRONT_PUBLIC_SAVE + 1; private const int FRONT_PRIVATE_SAVE = FRONT_SUB_BANNER + 1; private const int REAR_BANNER = 200; // ブロック内データ本体の後 private const int REAR_HEADER = 201; private const int REAR_SIGNATURE = 202; private const int REAR_TMD = 203; private const int REAR_CONTENT = 204; private const int REAR_PUBLIC_SAVE = REAR_CONTENT + MAX_CONTENTS; private const int REAR_SUB_BANNER = REAR_PUBLIC_SAVE + 1; private const int REAR_PRIVATE_SAVE = REAR_SUB_BANNER + 1; private const int REAR_DATA = 99; // データ全体の後 // 改ざんパターンの引き数 private const int MODE_ALL = 0; private const int MODE_CAT100 = 1; private const int MODE_CAT200 = 2; private const int MODE_CAT300 = 3; private const int MODE_CAT400 = 4; private const int MODE_CAT500 = 5; private const int MODE_VERIFY = 9; // 各カテゴリでの最小番号 private const int MIN_OF_CAT100 = 100; private const int MIN_OF_CAT200 = 200; private const int MIN_OF_CAT300 = 300; private const int MIN_OF_CAT400 = 400; private const int MIN_OF_CAT500 = 500; // 各カテゴリでの最大番号 private const int MAX_OF_CAT100 = 121; private const int MAX_OF_CAT200 = 218; private const int MAX_OF_CAT300 = 303; private const int MAX_OF_CAT400 = 419; private const int MAX_OF_CAT500 = 519; private static readonly int[,] NUM_OF_PATTERN = new int[,] { {100, MAX_OF_CAT100}, {200, MAX_OF_CAT200}, {300, MAX_OF_CAT300}, {400, MAX_OF_CAT400}, {500, MAX_OF_CAT500} }; // MACとハッシュセット更新の有無 private const int NC_MAC_AND_HASHSET = 0; private const int CHG_MAC_AND_HASHSET = 1; private const int BLOCK_NUM = 15; // バックアップデータのブロックの個数 private const int IMPROPER_DATA_SIZE = 16 * 1024; // 不正なデータのサイズ(16 KB) private const int KEY_SIZE = 16; // 鍵のサイズ(16 Byte) private const int HASH_SIZE = 32; // ハッシュのサイズ(32 Byte) private const int AES_BLOCK_SIZE = 16 * 8; // 暗号化のブロックサイズ(16Byte) private const string EXTENSION = ".bin"; // TwlBackupファイルの拡張子 /// /// 使用方法を表示します。 /// static void Usage() { Console.WriteLine("Usage: "); Console.WriteLine("./FalsifyingTwlBackup.exe BACKUP_FILE ENC_KEY_FILE MAC_KEY_FILE [-mode MODE] [-type TYPE]"); Console.WriteLine(" BACKUP_FILE : *.bin"); Console.WriteLine(" ENC_KEY_FILE : *.txt"); Console.WriteLine(" MAC_KEY_FILE : *.txt"); Console.WriteLine(); Console.WriteLine(" MODE"); Console.WriteLine(" all (default) : output all falsifying pattern"); Console.WriteLine(" cat:CAT_NUM : output all pattern of CAT_NUM category"); Console.WriteLine(" ex) -mode cat:100 -> falsifying 100,101,102...."); Console.WriteLine(" each:PAT_NUM : output PAT_NUM pattern"); Console.WriteLine(" ex) -mode each:204 -> falsifying 204 only"); Console.WriteLine(" verify : verify backup file"); Console.WriteLine(); Console.WriteLine(" TYPE"); Console.WriteLine(" normal (default) : normal bkp type"); Console.WriteLine(" wps : bkp with private save type"); Console.WriteLine(" legacy : legacy bkp type"); Environment.Exit(-1); } /// /// 拡張子の判別を行います。 /// /// 確認対象となるファイル名 /// 拡張子 static void CheckExtension(string args, string extension) { Debug.Assert(args.Length > extension.Length); if (args.ToLower().EndsWith(extension) == false) { Console.WriteLine("{0} is not [\"{1}\"] file!", args, extension); Usage(); } return; } /// /// ファイルの有無を確認します。 /// /// 確認対象となるファイルのパス static void CheckFileExists(string args) { Debug.Assert(args.Length != 0); if (!File.Exists(args)) { Console.WriteLine("\"{0}\" is not exists!\n", args); Usage(); } } /// /// コマンドライン引数のオプションから処理を決定するためのフラグを立てる /// /// コマンドライン引数の格納された文字列 /// 処理判別のためのフラグ static int GetFalsifyingMode(string arg) { const string PREFIX_STR_CAT = "CAT:"; const string PREFIX_STR_EACH = "EACH:"; // all のとき if (arg.ToUpper() == "ALL") { return MODE_ALL; } // cat:xxx のとき else if (arg.Length > PREFIX_STR_CAT.Length && arg.ToUpper().Substring(0, PREFIX_STR_CAT.Length) == PREFIX_STR_CAT) { switch (arg.Substring(PREFIX_STR_CAT.Length, "XXX".Length)) { case "100": return MODE_CAT100; case "200": return MODE_CAT200; case "300": return MODE_CAT300; case "400": return MODE_CAT400; case "500": return MODE_CAT500; default: Usage(); break; // never reach } } // each:xxx のとき else if (arg.Length > PREFIX_STR_EACH.Length && arg.ToUpper().Substring(0, PREFIX_STR_EACH.Length) == PREFIX_STR_EACH) { // TODO 存在しない処理番号をはじくように return Convert.ToInt16(arg.Substring(PREFIX_STR_EACH.Length)); } // -verify else if (arg.ToUpper() == "VERIFY") { return MODE_VERIFY; } // それ以外 return MODE_ALL; } /// /// コマンドライン引数のオプションからバックアップ形式を指定する /// /// コマンドライン引数の格納された文字列 /// 処理判別のためのフラグ static BkpType GetBackupType(string arg) { // normal のとき if (arg.ToUpper() == "NORMAL") { return BkpType.NORMAL; } // wps のとき if (arg.ToUpper() == "WPS") { return BkpType.WITH_PRIVATE_SAVE; } // legacy のとき if (arg.ToUpper() == "LEGACY") { return BkpType.LEGACY; } // それ以外 return BkpType.NORMAL; } //================================================== // メイン関数 //================================================== static void Main(string[] args) { // コマンドライン引数の数チェック if (args.Length < 3) // データ、ブロック鍵、MAC鍵 { Usage(); return; } else { // 拡張子の判定 CheckExtension(args[0], ".bin"); // 入力ファイル名 CheckExtension(args[1], ".txt"); // ブロック鍵ファイル名 CheckExtension(args[2], ".txt"); // MAC鍵ファイル名 // ファイルが存在するかを確認 for (int i = 0; i < 3; i++) { CheckFileExists(args[i]); } } string twlBackupName = args[0]; string keyName = args[1]; string macKeyData = args[2]; int falsifyingMode = MODE_ALL; bool isSpecifyMode = false; if (args.Length >= 5 && args[3].ToUpper().TrimStart('-') == "MODE") { falsifyingMode = GetFalsifyingMode(args[4]); // オプションがあれば、改ざんのパターン決定 isSpecifyMode = true; } Properties prop = new Properties(); // インスタンスの作成 int argTypeIndex = (isSpecifyMode) ? 6 : 4; prop.bkpType = BkpType.NORMAL; prop.indexPublicSave = (int)Utility.SectionIndex.PUBLIC_SAVE; prop.indexSubBanner = (int)Utility.SectionIndex.SUB_BANNER; if (args.Length >= argTypeIndex + 1 && args[argTypeIndex - 1].ToUpper().TrimStart('-') == "TYPE") { prop.bkpType = GetBackupType(args[argTypeIndex]); } if (prop.bkpType == BkpType.LEGACY) { prop.indexPublicSave = (int)Utility.SectionIndexLegacy.PUBLIC_SAVE; prop.indexSubBanner = (int)Utility.SectionIndexLegacy.SUB_BANNER; } // バックアップデータの読み込み byte[] twlBackupData = File.ReadAllBytes(twlBackupName); // 鍵データの読み込み string[] keyString = File.ReadAllLines(keyName); prop.keyData = new byte[KEY_SIZE]; for (int i = 0; i < prop.keyData.Length; i++) { prop.keyData[i] = Convert.ToByte(keyString[i], 16); } // MAC鍵データの読み込み string[] macKeyString = File.ReadAllLines(macKeyData); prop.macKeyData = new byte[KEY_SIZE]; for (int i = 0; i < prop.keyData.Length; i++) { prop.macKeyData[i] = Convert.ToByte(macKeyString[i], 16); } // ファイル名の出力 + 鍵データの dump Console.WriteLine("Twl Backup File : {0}", twlBackupName); Console.WriteLine("Block Key File : {0} ({1})", keyName, dumpArray(prop.keyData)); Console.WriteLine("MAC Key File : {0} ({1})", macKeyData, dumpArray(prop.macKeyData)); Console.WriteLine(); Console.WriteLine("Mode : {0}", getModeString(falsifyingMode)); Console.WriteLine("Type : {0}", getBackupTypeString(prop.bkpType)); Console.WriteLine(); // ひとまず VERIFY だったら検証して終了 if (falsifyingMode == MODE_VERIFY) { if (Utility.Verify(twlBackupData, prop.keyData, prop.macKeyData, prop.bkpType)) { Console.WriteLine("{0} は検証に成功しました。", twlBackupName); } Environment.Exit(0); } // バックアップデータを復号化 prop.decryptedBlocks = Utility.DecryptBackupData(twlBackupData, prop.keyData, prop.bkpType); // 出力フォルダを作成 prop.SetOutputFolderPath(twlBackupName); //========================================== // 改ざん&ファイル出力 Console.WriteLine("Start ------------"); SwitchFalsifyingPattern(falsifyingMode, prop); Console.WriteLine("Complete --------"); Console.WriteLine("Output Dir: {0}", prop.outFolderPath); } // byte 配列の 16 進表示 static string dumpArray(byte[] array) { string str = ""; foreach (byte b in array) { str += String.Format("{0,0:X2} ", b); } return str.TrimEnd(); } // mode の文字列を取得 static string getModeString(int mode) { switch (mode) { case MODE_ALL: return "ALL"; case MODE_CAT100: return "CATEGORY 1XX"; case MODE_CAT200: return "CATEGORY 2XX"; case MODE_CAT300: return "CATEGORY 3XX"; case MODE_CAT400: return "CATEGORY 4XX"; case MODE_CAT500: return "CATEGORY 5XX"; case MODE_VERIFY: return "VERIFY"; default: return ""; } } // type の文字列を取得 static string getBackupTypeString(BkpType type) { switch (type) { case BkpType.NORMAL : return "NORMAL"; case BkpType.WITH_PRIVATE_SAVE : return "WITH_PRIVATE_SAVE"; case BkpType.LEGACY : return "LEGACY"; default: return ""; } } } }