Ejemplo n.º 1
0
        public void TestOdkIndexEnumConversion()
        {
            var redSuccess0          = DurangoKeys.GetOdkIndexFromString("RedOdk", out OdkIndex redOdk);
            var redSuccess1          = DurangoKeys.GetOdkIndexFromString("redodk", out OdkIndex redOdkLower);
            var redSuccess2          = DurangoKeys.GetOdkIndexFromString("2", out OdkIndex redOdkNumber);
            var standardSuccess      = DurangoKeys.GetOdkIndexFromString("0", out OdkIndex standardOdkNumber);
            var unknownNumberSuccess = DurangoKeys.GetOdkIndexFromString("42", out OdkIndex unknownOdkNumber);

            var invalidNameFail = DurangoKeys.GetOdkIndexFromString("redodkblabla", out OdkIndex nameFail);

            Assert.True(redSuccess0);
            Assert.True(redSuccess1);
            Assert.True(redSuccess2);
            Assert.True(standardSuccess);
            Assert.True(unknownNumberSuccess);

            Assert.False(invalidNameFail);

            Assert.Equal(OdkIndex.RedOdk, redOdk);
            Assert.Equal(OdkIndex.RedOdk, redOdkLower);
            Assert.Equal(OdkIndex.RedOdk, redOdkNumber);
            Assert.Equal((OdkIndex)42, unknownOdkNumber);

            Assert.Equal(OdkIndex.Invalid, nameFail);
        }
Ejemplo n.º 2
0
        public bool ResignWithRedKey()
        {
            var key = DurangoKeys.GetSignkeyByName("RedXvdPrivateKey");

            if (key == null || !key.HasKeyData)
            {
                throw new InvalidOperationException("Private Xvd Red key is not loaded, cannot resign xvd header");
            }

            return(Resign(key.KeyData, "RSAFULLPRIVATEBLOB"));
        }
Ejemplo n.º 3
0
        private void CryptHeaderCik(bool encrypt)
        {
            if ((!encrypt && CikIsDecrypted) || IsXvcFile)
            {
                CikIsDecrypted = true;
                return;
            }

            var odkToUse = OverrideOdk == OdkIndex.Invalid ? Header.ODKKeyslotID : OverrideOdk;

            var odkKey = DurangoKeys.GetOdkById(odkToUse);

            if (odkKey == null)
            {
                throw new InvalidOperationException(
                          $"ODK with Id \'{Header.ODKKeyslotID}\' not found! Cannot crypt CIK in header");
            }

            if (!odkKey.HasKeyData)
            {
                throw new InvalidOperationException(
                          $"ODK with Id \'{Header.ODKKeyslotID}\' is known but not loaded! Cannot crypt CIK in header");
            }

            byte[] nullIv = new byte[16];

            var cipher = Aes.Create();

            cipher.Mode    = CipherMode.ECB;
            cipher.Padding = PaddingMode.None;

            var transform = encrypt ? cipher.CreateEncryptor(odkKey.KeyData, nullIv) :
                            cipher.CreateDecryptor(odkKey.KeyData, nullIv);

            transform.TransformBlock(Header.KeyMaterial, 0, Header.KeyMaterial.Length, Header.KeyMaterial, 0);

            CikIsDecrypted = !encrypt;
        }
Ejemplo n.º 4
0
        public int PullKeysFromFile()
        {
            var exeData = File.ReadAllBytes(FilePath);

            int foundCount = 0;

            for (int i = 0; i < exeData.Length - 32; i++)
            {
                byte[]          hash32 = HashUtils.ComputeSha256(exeData, i, 32);
                DurangoKeyEntry keyEntry;
                foreach (var kvp in DurangoKeys.GetAllXvdSigningKeys())
                {
                    string keyName = kvp.Key;
                    keyEntry = kvp.Value;

                    if (keyEntry.HasKeyData)
                    {
                        continue;
                    }
                    if (keyEntry.DataSize > exeData.Length - i)
                    {
                        continue;
                    }

                    byte[] signKeyHash = HashUtils.ComputeSha256(exeData, i, keyEntry.DataSize);

                    if (!keyEntry.SHA256Hash.IsEqualTo(signKeyHash))
                    {
                        continue;
                    }

                    Console.WriteLine($"Found {keyEntry.KeyType} \"{keyName}\" at offset 0x{i:X}");

                    byte[] keyData = new byte[keyEntry.DataSize];
                    Array.Copy(exeData, i, keyData, 0, keyData.Length);

                    DurangoKeys.LoadSignKey(keyName, keyData, out bool newKey, out keyName);
                    foundCount++;
                }

                foreach (var kvp in DurangoKeys.GetAllODK())
                {
                    OdkIndex keyId = kvp.Key;
                    keyEntry = kvp.Value;

                    if (keyEntry.HasKeyData)
                    {
                        continue;
                    }

                    if (!hash32.IsEqualTo(keyEntry.SHA256Hash))
                    {
                        continue;
                    }

                    Console.WriteLine($"Found {keyEntry.KeyType} \"{keyId}\" at offset 0x{i:X}");

                    byte[] keyData = new byte[keyEntry.DataSize];
                    Array.Copy(exeData, i, keyData, 0, keyData.Length);

                    DurangoKeys.LoadOdkKey(keyId, keyData, out bool newKey);
                    foundCount++;
                }

                foreach (var kvp in DurangoKeys.GetAllCIK())
                {
                    Guid keyId = kvp.Key;
                    keyEntry = kvp.Value;

                    if (keyEntry.HasKeyData)
                    {
                        continue;
                    }

                    if (!hash32.IsEqualTo(keyEntry.SHA256Hash))
                    {
                        continue;
                    }

                    Console.WriteLine($"Found {keyEntry.KeyType} \"{keyId}\" at offset 0x{i:X}");

                    byte[] keyData = new byte[0x10 + keyEntry.DataSize];
                    Array.Copy(keyId.ToByteArray(), 0, keyData, 0, 0x10);
                    Array.Copy(exeData, i, keyData, 0x10, keyEntry.DataSize);

                    DurangoKeys.LoadCikKeys(keyData, out Guid[] keyGuid);
                    foundCount++;
                }
            }

            return(foundCount);
        }
Ejemplo n.º 5
0
        public bool SaveFoundKeys(string destinationDirectory)
        {
            string path;

            foreach (var keyType in Enum.GetNames(typeof(KeyType)))
            {
                path = Path.Combine(destinationDirectory, $"{keyType}");
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
            }

            /* Xvd signing keys */
            foreach (var kvp in DurangoKeys.GetAllXvdSigningKeys())
            {
                IKeyEntry keyEntry = kvp.Value;

                if (!keyEntry.HasKeyData)
                {
                    continue;
                }

                path = Path.Combine(destinationDirectory, $"{KeyType.XvdSigningKey}", $"{kvp.Key}.rsa");
                File.WriteAllBytes(path, keyEntry.KeyData);
            }

            /* ODK */
            foreach (var kvp in DurangoKeys.GetAllODK())
            {
                IKeyEntry keyEntry = kvp.Value;

                if (!keyEntry.HasKeyData)
                {
                    continue;
                }

                path = Path.Combine(destinationDirectory, $"{KeyType.Odk}", $"{kvp.Key}.odk");
                File.WriteAllBytes(path, keyEntry.KeyData);
            }

            /* CIK */
            foreach (var kvp in DurangoKeys.GetAllCIK())
            {
                IKeyEntry keyEntry = kvp.Value;

                if (!keyEntry.HasKeyData)
                {
                    continue;
                }

                path = Path.Combine(destinationDirectory, $"{KeyType.Cik}", $"{kvp.Key}.cik");

                byte[] keyData = new byte[0x30];
                Array.Copy(kvp.Key.ToByteArray(), 0, keyData, 0, 0x10);
                Array.Copy(keyEntry.KeyData, 0, keyData, 0x10, 0x20);

                File.WriteAllBytes(path, keyData);
            }

            return(true);
        }
Ejemplo n.º 6
0
        static void Main(string[] args)
        {
            const string fmt = "    ";

            var outputFile   = String.Empty;
            var fileList     = String.Empty;
            var folder       = String.Empty;
            var exvdDest     = String.Empty;
            var userDataDest = String.Empty;
            var vhdDest      = String.Empty;
            var rawimageDest = String.Empty;
            var fsDest       = String.Empty;

            var signKeyToUse = String.Empty;
            var odkToUse     = OdkIndex.Invalid;
            var cikToUse     = Guid.Empty;

            var signKeyFilepath = String.Empty;
            var odkFilepath     = String.Empty;
            var cikFilepath     = String.Empty;

            bool listKeys = false;

            string mountPoint = null;

            var mountPackage   = false;
            var unmountPackage = false;

            var decryptPackage = false;
            var encryptPackage = false;
            var rehashPackage  = false;
            var resignPackage  = false;
            var addHashTree    = false;
            var removeHashTree = false;
            var addMdu         = false;
            var removeMdu      = false;
            var printInfo      = false;
            var writeInfo      = false;
            var printHelp      = false;

            var disableDataExtract = false;

            XvdFile.PrintProgressToConsole       = true;
            XvdFile.DisableSaveAfterModification = true;

            var p = new OptionSet {
                { "h|?|help", v => printHelp = v != null },
                { "i|info", v => printInfo = v != null },
                { "wi|writeinfo", v => writeInfo = v != null },
                { "o|output=", v => outputFile = v },

                { "m|mount", v => mountPackage = v != null },
                { "um|unmount", v => unmountPackage = v != null },
                { "mp|mountpoint=", v => mountPoint = v },

                { "lk|listkeys", v => listKeys = v != null },

                { "signfile=", v => signKeyFilepath = v },
                { "odkfile=", v => odkFilepath = v },
                { "cikfile=", v => cikFilepath = v },

                { "sk|signkey=", v => signKeyToUse = v },
                { "odk|odkid=", v =>
                  {
                      if (!DurangoKeys.GetOdkIndexFromString(v, out odkToUse))
                      {
                          throw new OptionException("Invalid Odk Id", "odkid");
                      }
                  } },
                { "cik|cikguid=", v =>
                  {
                      if (!Guid.TryParse(v, out cikToUse))
                      {
                          throw new OptionException("Invalid CIK GUID", "cikguid");
                      }
                  } },
                { "nd|nodatahash", v => XvdFile.DisableDataHashChecking = v != null },
                { "ne|noextract", v => disableDataExtract = v != null },

                { "r|rehash", v => rehashPackage = v != null },
                { "rs|resign", v => resignPackage = v != null },

                { "eu|decrypt", v => decryptPackage = v != null },
                { "ee|encrypt", v => encryptPackage = v != null },
                { "hd|removehash|removehashtree", v => removeHashTree = v != null },
                { "he|addhash|addhashtree", v => addHashTree = v != null },
                { "md|removemdu", v => removeMdu = v != null },
                { "ma|addmdu", v => addMdu = v != null },

                { "xe|extractembedded=", v => exvdDest = v },
                { "xu|extractuserdata=", v => userDataDest = v },
                { "xv|extractvhd=", v => vhdDest = v },
                { "xi|extractimage=", v => rawimageDest = v },
                { "xf|extractfiles=", v => fsDest = v },

                { "l|filelist=", v => fileList = v },
                { "f|folder=", v => folder = v },
            };

            List <string> extraArgs;

            try
            {
                extraArgs = p.Parse(args);
            }
            catch (OptionException e)
            {
                Console.WriteLine($"Failed parsing parameter \'{e.OptionName}\': {e.Message}");
                Console.WriteLine("Try 'xvdtool --help' for more information");
                return;
            }

            Console.WriteLine($"XVDTool {AppVersion}: XVD file manipulator");

            if (printHelp || (String.IsNullOrEmpty(fileList) && String.IsNullOrEmpty(folder) && !listKeys && extraArgs.Count <= 0))
            {
                Console.WriteLine("Usage  : xvdtool.exe [parameters] [filename]");
                Console.WriteLine();
                Console.WriteLine("Parameters:");
                Console.WriteLine(fmt + "-h (-help) - print xvdtool usage");
                Console.WriteLine(fmt + "-i (-info) - print info about package");
                Console.WriteLine(fmt + "-wi (-writeinfo) - write info about package to [filename].txt");
                Console.WriteLine(fmt + "-o (-output) <output-path> - specify output filename");
                Console.WriteLine();
                Console.WriteLine(fmt + "-m (-mount) - mount package");
                Console.WriteLine(fmt + "-um (-unmount) - unmount package");
                Console.WriteLine(fmt + "-mp (-mountpoint) - Mount point for package (e.g. \"X:\")");
                Console.WriteLine();
                Console.WriteLine(fmt + "-lk (-listkeys) - List known keys including their hashes / availability");
                Console.WriteLine();
                Console.WriteLine(fmt + "-signfile <path-to-file> - Path to xvd sign key (RSA)");
                Console.WriteLine(fmt + "-odkfile <path-to-file> - Path to Offline Distribution key");
                Console.WriteLine(fmt + "-cikfile <path-to-file> - Path to Content Instance key");
                Console.WriteLine();
                Console.WriteLine(fmt + "-sk (-signkey) <key-name> - Name of xvd sign key to use");
                Console.WriteLine(fmt + "-odk (-odkid) <id> - Id of Offline Distribution key to use (uint)");
                Console.WriteLine(fmt + "-cik (-cikguid) <GUID> - Guid of Content Instance key to use");
                Console.WriteLine();
                Console.WriteLine(fmt + "-nd (-nodatahash) - disable data hash checking, speeds up -l and -f");
                Console.WriteLine(fmt + "-ne (-noextract) - disable data (embedded XVD/user data) extraction, speeds up -l and -f");
                Console.WriteLine();
                Console.WriteLine(fmt + "-eu (-decrypt) - decrypt output xvd");
                Console.WriteLine(fmt + "-ee (-encrypt) - encrypt output xvd");
                Console.WriteLine(fmt + fmt +
                                  "XVDs will have a new CIK generated (if CIK in XVD header is empty), which will be encrypted with the ODK and stored in the XVD header");
                Console.WriteLine();
                Console.WriteLine(fmt + "-hd (-removehash) - remove hash tree/data integrity from package");
                Console.WriteLine(fmt + "-he (-addhash) - add hash tree/data integrity to package");
                Console.WriteLine();
                Console.WriteLine(fmt + "-md (-removemdu) - remove mutable data (MDU) from package");
                Console.WriteLine(fmt + "-ma (-addmdu) - add mutable data (MDU) to package");
                Console.WriteLine();
                Console.WriteLine(fmt + "-r (-rehash) - fix data integrity hashes inside package");
                Console.WriteLine(fmt + "-rs (-resign) - sign package using the private key from rsa3_key.bin");
                Console.WriteLine();
                Console.WriteLine(fmt + "-xe (-extractembedded) <output-file> - extract embedded XVD from package");
                Console.WriteLine(fmt + "-xu (-extractuserdata) <output-file> - extract user data from package");
                Console.WriteLine(fmt + "-xv (-extractvhd) <output-vhd> - extracts filesystem from XVD into a VHD file");
                Console.WriteLine(fmt + "-xi (-extractimage) <output-file> - extract raw filesystem image");
                Console.WriteLine(fmt + "-xf (-extractfiles) <output-folder> - extract files from XVD filesystem");
                Console.WriteLine();
                Console.WriteLine(fmt + "The next two commands will write info about each package found to [filename].txt");
                Console.WriteLine(fmt + "also extracts embedded XVD and user data to [filename].exvd.bin / [filename].userdata.bin");
                Console.WriteLine(fmt + "-l (-filelist) <path-to-file-list> - use each XVD specified in the list");
                Console.WriteLine(fmt + "-f (-folder) <path-to-folder> - scan folder for XVD files");
                Console.WriteLine();
                Console.WriteLine(@"To mount a package in Windows you'll have to decrypt it and remove the hash tables & mutable data first (-eu -hd -md)");
                return;
            }

            Console.WriteLine();

            var fallbackCik     = DurangoKeys.TestCIK;
            var fallbackSignKey = DurangoKeys.RedXvdPrivateKey;

            var localConfigDir = AppDirs.GetApplicationConfigDirectory(AppName);
            var executableDir  = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            /* If necessary, create folders to store keys */
            EnsureConfigDirectoryStructure(localConfigDir);
            EnsureConfigDirectoryStructure(executableDir);

            /* Load keys from global and local config directory */
            DurangoKeys.LoadKeysRecursive(localConfigDir);
            DurangoKeys.LoadKeysRecursive(executableDir);

            /* Check key parameters */
            if (signKeyFilepath != String.Empty)
            {
                if (!DurangoKeys.LoadKey(KeyType.XvdSigningKey, signKeyFilepath))
                {
                    Console.WriteLine($"Failed to load SignKey from {signKeyFilepath}");
                    return;
                }
            }
            if (odkFilepath != String.Empty)
            {
                if (!DurangoKeys.LoadKey(KeyType.Odk, odkFilepath))
                {
                    Console.WriteLine($"Failed to load ODK key from {odkFilepath}");
                    return;
                }
            }

            if (cikFilepath != String.Empty)
            {
                if (!DurangoKeys.LoadKey(KeyType.Cik, cikFilepath))
                {
                    Console.WriteLine($"Failed to load CIK from {cikFilepath}");
                    return;
                }
            }

            if (signKeyToUse == String.Empty)
            {
                Console.WriteLine($"No desired signkey provided, falling back to {fallbackSignKey}");
                signKeyToUse = fallbackSignKey;
            }

            if (cikToUse == Guid.Empty)
            {
                Console.WriteLine($"No desired CIK provided, falling back to {fallbackCik}");
                cikToUse = fallbackCik;
            }

            if (odkToUse == OdkIndex.Invalid)
            {
                Console.WriteLine("No desired or invalid ODK provided, will try to use ODK indicated by XVD header");
            }
            else if (!DurangoKeys.IsOdkLoaded(odkToUse))
            {
                Console.WriteLine($"Warning: ODK {odkToUse} could not be loaded!");
            }
            else
            {
                Console.WriteLine($"Using ODK: {odkToUse}");
            }

            Console.WriteLine(!DurangoKeys.IsSignkeyLoaded(signKeyToUse)
                ? "Warning: Signkey could not be loaded, you will be unable to resign XVD headers!"
                : $"Using Xvd Signkey: {signKeyToUse}");

            Console.WriteLine(!DurangoKeys.IsCikLoaded(cikToUse)
                ? "Warning: CIK could not be loaded!"
                : $"Using CIK: {cikToUse}");

            Console.WriteLine();

            if (listKeys)
            {
                void PrintKnownKeys <T>(KeyType type, KeyValuePair <T, DurangoKeyEntry>[] keyCollection)
                {
                    Console.WriteLine($"{type}:");
                    foreach (var keyKvp in keyCollection)
                    {
                        Console.WriteLine(fmt + $"{keyKvp.Key}: {keyKvp.Value}");
                    }
                }

                Console.WriteLine("Known Durango keys:");
                PrintKnownKeys(KeyType.XvdSigningKey, DurangoKeys.GetAllXvdSigningKeys());
                PrintKnownKeys(KeyType.Odk, DurangoKeys.GetAllODK());
                PrintKnownKeys(KeyType.Cik, DurangoKeys.GetAllCIK());
                return;
            }

            /* Write out xvd info / extract data from provided folderpath */
            if (!String.IsNullOrEmpty(folder))
            {
                IEnumerable <string> files = ScanFolderForXvds(folder, true);
                foreach (string filename in files)
                {
                    var xvd = new XvdFile(filename);
                    xvd.Load();
                    try
                    {
                        File.WriteAllText(filename + ".txt", xvd.ToString(true));
                    }
// ReSharper disable once EmptyGeneralCatchClause
                    catch
                    {
                    }

                    if (!disableDataExtract)
                    {
                        if (xvd.Header.EmbeddedXVDLength > 0)
                        {
                            File.WriteAllBytes(filename + ".exvd.bin", xvd.ExtractEmbeddedXvd());
                        }

                        if (xvd.Header.UserDataLength > 0 && !xvd.IsEncrypted)
                        {
                            File.WriteAllBytes(filename + ".userdata.bin", xvd.ExtractUserData());
                        }
                    }
                    xvd.Dispose();
                }
                return;
            }

            /* Write out xvd info / extract data from provided filelist */
            if (!String.IsNullOrEmpty(fileList))
            {
                string[] files = File.ReadAllLines(fileList);
                foreach (string filename in files)
                {
                    var xvd = new XvdFile(filename);
                    xvd.Load();
                    File.WriteAllText(filename + ".txt", xvd.ToString(true));

                    if (!disableDataExtract)
                    {
                        if (xvd.Header.EmbeddedXVDLength > 0)
                        {
                            File.WriteAllBytes(filename + ".exvd.bin", xvd.ExtractEmbeddedXvd());
                        }

                        if (xvd.Header.UserDataLength > 0 && !xvd.IsEncrypted)
                        {
                            File.WriteAllBytes(filename + ".userdata.bin", xvd.ExtractUserData());
                        }
                    }

                    xvd.Dispose();
                }
                return;
            }

            /* Handle input xvd */
            if (extraArgs.Count <= 0)
            {
                return;
            }

            string filePath = extraArgs[0];

            if (!File.Exists(filePath))
            {
                Console.WriteLine(@"Error: input file doesn't exist");
                return;
            }

            if (!String.IsNullOrEmpty(outputFile))
            {
                if (File.Exists(outputFile))
                {
                    Console.WriteLine(@"Error: output file already exists.");
                    return;
                }
                Console.WriteLine("Copying original file to output destination...");
                File.Copy(filePath, outputFile);
                filePath = outputFile;
            }

            if (mountPackage)
            {
                bool success = XvdMount.MountXvd(filePath, mountPoint);
                Console.WriteLine("Mounting {0} {1}", filePath, success ?
                                  "completed successfully" :
                                  "failed with error"
                                  );
                return;
            }

            if (unmountPackage)
            {
                bool success = XvdMount.UnmountXvd(filePath);
                Console.WriteLine("Unmounting {0} {1}", filePath, success ?
                                  "completed successfully" :
                                  "failed with error"
                                  );
                return;
            }

            Console.WriteLine($"Loading file from {filePath}...");
            Console.WriteLine();

            bool PerformActions(XvdFile file)
            {
                bool fileModified = false;

                if (printInfo || writeInfo)
                {
                    string info = file.ToString(true);
                    if (writeInfo)
                    {
                        File.WriteAllText(filePath + ".txt", info);
                        Console.WriteLine($"Wrote package info to \"{filePath}.txt\"");
                    }
                    else
                    {
                        Console.WriteLine(info);
                    }
                }

                if (addHashTree)
                {
                    if (file.IsDataIntegrityEnabled)
                    {
                        Console.WriteLine("Warning: -addhashtree failed as package already has a hash tree.");
                    }
                    else
                    {
                        Console.WriteLine("Attempting to add hash tree to package...");
                        bool success = file.AddHashTree();
                        Console.WriteLine(success
                            ? "Hash tree added successfully and header updated."
                            : "Error: failed to extend package to make room for hash tree, is there enough disk space?");
                        if (!success)
                        {
                            return(fileModified);
                        }
                        fileModified = true;
                    }
                }

                if (encryptPackage)
                {
                    if (file.IsEncrypted)
                    {
                        Console.WriteLine("Warning: -encrypt failed as package is already encrypted");
                    }
                    else
                    {
                        string keyToUse = "ODK";
                        if (file.IsXvcFile)
                        {
                            var cikKeys   = DurangoKeys.GetAllCIK();
                            var chosenKey = cikKeys.Single(kvp => kvp.Key == cikToUse).Value;
                            if (chosenKey == null)
                            {
                                Console.WriteLine(
                                    "Error: Invalid CIK key \"{encryptKeyId}\" specified, make sure said key exists!");
                                return(fileModified);
                            }

                            keyToUse = $"CIK:{cikToUse}";
                        }

                        Console.WriteLine($"Encrypting package using \"{keyToUse}\" key...");
                        bool success = file.Encrypt(cikToUse);
                        Console.WriteLine(success
                            ? "Package encrypted successfully!"
                            : "Error during encryption!");
                        if (!success)
                        {
                            return(fileModified);
                        }
                        fileModified = true;
                    }
                }

                if (decryptPackage)
                {
                    if (!file.IsEncrypted)
                    {
                        Console.WriteLine(@"Warning: -decrypt failed as package is already decrypted");
                    }
                    else
                    {
                        if (file.IsXvcFile)
                        {
                            Console.WriteLine("Decrypting XVC...");
                        }
                        else
                        {
                            string keyToUse = odkToUse != OdkIndex.Invalid
                                ? odkToUse.ToString()
                                : "<ODK indicated by XVD header>";
                            Console.WriteLine($"Decrypting XVD using \"{keyToUse}\" key...");
                        }

                        bool success = file.Decrypt();
                        Console.WriteLine(success
                            ? "Package decrypted successfully!"
                            : "Error during decryption!");
                        if (!success)
                        {
                            return(fileModified);
                        }
                        fileModified = true;
                    }
                }

                if (removeHashTree)
                {
                    if (!file.IsDataIntegrityEnabled)
                    {
                        Console.WriteLine("Warning: -removehashtree failed as package doesn't have a hash tree.");
                    }
                    else
                    {
                        Console.WriteLine("Attempting to remove hash tree from package...");
                        bool success = file.RemoveHashTree();
                        Console.WriteLine(success
                            ? "Hash tree removed successfully and header updated."
                            : "Error: hash tree is larger than input package (???)");
                        if (!success)
                        {
                            return(fileModified);
                        }
                        fileModified = true;
                    }
                }

                if (removeMdu)
                {
                    if (file.Header.MutableDataPageCount <= 0)
                    {
                        Console.WriteLine("Warning: -removemdu failed as package doesn't have any mutable data.");
                    }
                    else
                    {
                        Console.WriteLine("Removing mutable data from package...");
                        bool success = file.RemoveMutableData();
                        Console.WriteLine(success
                            ? "Mutable data removed successfully and header updated."
                            : "Failed to remove mutable data?");
                        if (!success)
                        {
                            return(fileModified);
                        }
                        fileModified = true;
                    }
                }

                if (addMdu)
                {
                    if (file.Header.MutableDataPageCount > 0)
                    {
                        Console.WriteLine("Warning: -addmdu failed as package already has mutable data.");
                    }
                    else
                    {
                        Console.WriteLine("Adding mutable data to package...");
                        bool success = file.AddMutableData();
                        Console.WriteLine(success
                            ? "Mutable data added successfully and header updated."
                            : "Failed to add mutable data?");
                        if (!success)
                        {
                            return(fileModified);
                        }
                        fileModified = true;
                    }
                }

                if (rehashPackage)
                {
                    if (!file.IsDataIntegrityEnabled)
                    {
                        Console.WriteLine("Warning: -rehash failed as package doesn't have a hash tree.");
                    }
                    else
                    {
                        Console.WriteLine($"Old top hash block hash: {file.Header.TopHashBlockHash.ToHexString()}");
                        Console.WriteLine("Rehashing package...");
                        ulong[] fixedHashes = file.VerifyDataHashTree(true);
                        bool    success     = file.CalculateHashTree();
                        if (success)
                        {
                            Console.WriteLine($"New top hash block hash: {file.Header.TopHashBlockHash.ToHexString()}");
                        }

                        Console.WriteLine(success
                            ? $"Successfully rehashed {fixedHashes.Length} invalid data hashes inside package."
                            : "Error: there was a problem rehashing the package.");
                        if (!success)
                        {
                            return(fileModified);
                        }
                        fileModified = true;
                    }
                }

                if (resignPackage)
                {
                    var  key     = DurangoKeys.GetSignkeyByName(signKeyToUse);
                    bool success = file.Header.Resign(key.KeyData, "RSAFULLPRIVATEBLOB");
                    Console.WriteLine(success
                        ? "Successfully resigned package."
                        : "Error: there was a problem resigning the package.");
                    if (!success)
                    {
                        return(fileModified);
                    }
                    fileModified = true;
                }

                if (!String.IsNullOrEmpty(exvdDest))
                {
                    byte[] exvd = file.ExtractEmbeddedXvd();
                    if (exvd == null || exvd.Length <= 0)
                    {
                        Console.WriteLine(
                            "Warning: -extractembedded failed as package doesn't contain an embedded XVD.");
                    }
                    else
                    {
                        try
                        {
                            File.WriteAllBytes(exvdDest, exvd);
                            Console.WriteLine(
                                $"Extracted embedded XVD to \"{exvdDest}\" successfully (0x{exvd.Length:X} bytes)");
                        }
                        catch
                        {
                            Console.WriteLine("Error: failed to extract embedded XVD.");
                        }
                    }
                }


                if (!String.IsNullOrEmpty(userDataDest))
                {
                    byte[] userData = file.ExtractUserData();
                    if (userData == null || userData.Length <= 0)
                    {
                        Console.WriteLine("Warning: -extractuserdata failed as package doesn't contain user data.");
                    }
                    else
                    {
                        try
                        {
                            File.WriteAllBytes(userDataDest, userData);
                            Console.WriteLine(
                                $"Extracted XVD user data to \"{userDataDest}\" successfully (0x{userData.Length:X} bytes)");
                        }
                        catch
                        {
                            Console.WriteLine("Error: failed to extract XVD user data.");
                        }
                    }
                }

                if (!String.IsNullOrEmpty(vhdDest))
                {
                    if (file.IsEncrypted)
                    {
                        Console.WriteLine("Warning: -extractvhd failed as package is still encrypted.");
                    }
                    else
                    {
                        Console.WriteLine($"Extracting XVD filesystem to VHD file \"{vhdDest}\"...");
                        bool success = file.Filesystem.ConvertToVhd(vhdDest);
                        Console.WriteLine(success
                            ? "Wrote VHD successfully."
                            : "Error: there was a problem extracting the filesystem from the XVD.");
                        if (!success)
                        {
                            return(fileModified);
                        }
                    }
                }

                if (!String.IsNullOrEmpty(rawimageDest))
                {
                    if (file.IsEncrypted)
                    {
                        Console.WriteLine("Warning: -extractimage failed as package is still encrypted.");
                    }
                    else
                    {
                        Console.WriteLine($"Extracting raw filesystem image to file \"{rawimageDest}\"...");
                        bool success = file.Filesystem.ExtractFilesystemImage(rawimageDest, false);
                        Console.WriteLine(success
                            ? "Extracted raw image successfully."
                            : "Error: there was a problem extracting raw image from the XVD.");
                        if (!success)
                        {
                            return(fileModified);
                        }
                    }
                }

                if (!String.IsNullOrEmpty(fsDest))
                {
                    if (file.IsEncrypted)
                    {
                        Console.WriteLine("Warning: -extractfiles failed as package is still encrypted.");
                    }
                    else
                    {
                        Console.WriteLine($"Extracting XVD files to folder \"{fsDest}\"...");
                        bool success = file.Filesystem.ExtractFilesystem(fsDest);
                        Console.WriteLine(success
                            ? "Extracted files successfully."
                            : "Error: there was a problem extracting the files from the XVD.");
                        if (!success)
                        {
                            return(fileModified);
                        }
                    }
                }

                return(fileModified);
            }

            var xvdFile = new XvdFile(filePath)
            {
                OverrideOdk = odkToUse
            };

            xvdFile.Load();

            if (PerformActions(xvdFile)) // PerformActions returns true if file has been modified
            {
                xvdFile.Save();
            }

            xvdFile.Dispose();
        }
Ejemplo n.º 7
0
        public bool Encrypt(Guid cikKeyId)
        {
            if (IsEncrypted)
            {
                return(true);
            }

            bool success;

            if (!IsXvcFile)
            {
                if (Header.KeyMaterial.IsArrayEmpty())
                {
                    // generate a new CIK if there's none specified
                    var rng = new Random();
                    Header.KeyMaterial = new byte[0x20];
                    rng.NextBytes(Header.KeyMaterial);
                }

                // todo: check with more non-xvc xvds and see if they use any other headerId besides 0x1
                success = CryptSectionXts(true, Header.KeyMaterial, 0x1, UserDataOffset,
                                          (ulong)_io.Stream.Length - UserDataOffset);
            }
            else
            {
                if (cikKeyId != Guid.Empty) // if cikKeyId is set, set the XvcInfo key accordingly
                {
                    var key = DurangoKeys.GetCikByGuid(cikKeyId);
                    if (key == null)
                    {
                        throw new InvalidOperationException($"Desired CIK with GUID {cikKeyId} is unknown");
                    }

                    if (!key.HasKeyData)
                    {
                        throw new InvalidOperationException($"Desired CIK with GUID {cikKeyId} is known but not loaded");
                    }

                    XvcInfo.EncryptionKeyIds[0].KeyId = cikKeyId.ToByteArray();
                }

                for (int i = 0; i < RegionHeaders.Count; i++)
                {
                    var header = RegionHeaders[i];
                    if (header.Length <= 0 || header.Offset <= 0 || header.KeyId + 1 > XvcInfo.KeyCount && header.KeyId != XvcConstants.XVC_KEY_NONE)
                    {
                        continue;
                    }

                    if (header.Id == XvcRegionId.Header ||
                        header.Id == XvcRegionId.EmbeddedXvd ||
                        header.Id == XvcRegionId.MetadataXvc)
                    {
                        continue; // skip XVD header / EXVD / XVC info
                    }
                    if (!CryptXvcRegion(i, true))
                    {
                        return(false);
                    }
                }
                success = true;
            }

            if (!success)
            {
                return(false);
            }

            CryptHeaderCik(true);

            Header.VolumeFlags ^= XvdVolumeFlags.EncryptionDisabled;

            // seems the readonly flag gets set when encrypting
            if (!Header.VolumeFlags.HasFlag(XvdVolumeFlags.ReadOnly))
            {
                Header.VolumeFlags ^= XvdVolumeFlags.ReadOnly;
            }

            Save();

            return(true);
        }
Ejemplo n.º 8
0
        public bool GetXvcKeyByGuid(Guid keyGuid, out byte[] keyOutput)
        {
            keyOutput = null;

            if (XvcInfo.EncryptionKeyIds == null || XvcInfo.EncryptionKeyIds.Length < 1 || XvcInfo.KeyCount == 0)
            {
                return(false);
            }

            bool keyFound = false;

            foreach (var xvcKey in XvcInfo.EncryptionKeyIds)
            {
                if (new Guid(xvcKey.KeyId) == keyGuid)
                {
                    keyFound = true;
                }
            }

            if (!keyFound)
            {
                Console.WriteLine($"Key {keyGuid} is not used by this XVC");
                return(false);
            }

            if (DurangoKeys.IsCikLoaded(keyGuid))
            {
                keyOutput = DurangoKeys.GetCikByGuid(keyGuid).KeyData;
                return(true);
            }

            Console.WriteLine($"Did not find CIK {keyGuid} loaded in Keystorage");
            Console.WriteLine("Checking for XML licenses...");

            string licenseFolder = Path.GetDirectoryName(FilePath);

            if (Path.GetFileName(licenseFolder) == "MSXC")
            {
                licenseFolder = Path.GetDirectoryName(licenseFolder);
            }

            if (String.IsNullOrEmpty(licenseFolder))
            {
                return(false);
            }

            licenseFolder = Path.Combine(licenseFolder, "Licenses");

            if (!Directory.Exists(licenseFolder))
            {
                return(false);
            }

            foreach (string file in Directory.GetFiles(licenseFolder, "*.xml"))
            {
                var xml = new XmlDocument();
                xml.Load(file);

                var xmlns = new XmlNamespaceManager(xml.NameTable);
                xmlns.AddNamespace("resp", "http://schemas.microsoft.com/xboxlive/security/clas/LicResp/v1");

                XmlNode licenseNode = xml.SelectSingleNode("//resp:SignedLicense", xmlns);
                if (licenseNode == null)
                {
                    continue;
                }

                string signedLicense      = licenseNode.InnerText;
                byte[] signedLicenseBytes = Convert.FromBase64String(signedLicense);

                var licenseXml = new XmlDocument();
                licenseXml.LoadXml(Encoding.ASCII.GetString(signedLicenseBytes));

                var xmlns2 = new XmlNamespaceManager(licenseXml.NameTable);
                xmlns2.AddNamespace("resp", "http://schemas.microsoft.com/xboxlive/security/clas/LicResp/v1");

                XmlNode keyIdNode = licenseXml.SelectSingleNode("//resp:KeyId", xmlns2);
                if (keyIdNode == null)
                {
                    continue;
                }

                if (keyGuid != new Guid(keyIdNode.InnerText))
                {
                    continue;
                }

                XmlNode licenseBlockNode = licenseXml.SelectSingleNode("//resp:SPLicenseBlock", xmlns2);
                if (licenseBlockNode == null)
                {
                    continue;
                }

                string licenseBlock      = licenseBlockNode.InnerText;
                byte[] licenseBlockBytes = Convert.FromBase64String(licenseBlock);

                var block      = new XvcLicenseBlock(licenseBlockBytes);
                var keyIdBlock = block.GetBlockWithId(XvcLicenseBlockId.KeyId);
                if (keyIdBlock == null)
                {
                    continue;
                }

                if (!(new Guid(keyIdBlock.BlockData) == keyGuid))
                {
                    continue;
                }

                var decryptKeyBlock = block.GetBlockWithId(XvcLicenseBlockId.EncryptedCik);
                if (decryptKeyBlock == null)
                {
                    continue;
                }

                keyOutput = decryptKeyBlock.BlockData;
                Console.WriteLine($"Xvd CIK key found in {file}");
                // todo: decrypt/deobfuscate the key

                return(true);
            }
            return(false);
        }