示例#1
0
文件: Program.cs 项目: Overx/xvdtool
        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 decryptPackage = false;
            var encryptPackage = false;
            var encryptKeyId = 0;
            var rehashPackage = false;
            var resignPackage = false;
            var addHashTree = false;
            var removeHashTree = false;
            var printInfo = false;
            var writeInfo = false;
            var printHelp = false;

            var disableDataExtract = false;

            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 },

                { "nd|nodatahash", v => XvdFile.DisableDataHashChecking = v != null },
                { "nn|nonatives", v => XvdFile.DisableNativeFunctions = 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;
                    if (!int.TryParse(v, out encryptKeyId))
                    {
                        Console.WriteLine("Error: invalid keyid specified for -encrypt");
                        System.Diagnostics.Process.GetCurrentProcess().Kill();
                    }
                } },

                { "hd|removehash|removehashtree", v => removeHashTree = v != null },
                { "he|addhash|addhashtree", v => addHashTree = v != null },

                { "xe|extractembedded=", v => exvdDest = v },
                { "xu|extractuserdata=", v => userDataDest = v },
                { "xv|extractvhd=", v => vhdDest = v },

                { "l|filelist=", v => fileList = v },
                { "f|folder=", v => folder = v },
            };
            var extraArgs = p.Parse(args);

            Console.WriteLine("xvdtool 0.4: XVD file manipulator");

            XvdFile.LoadKeysFromDisk();

            if(!XvdFile.SignKeyLoaded)
                Console.WriteLine("Warning: rsa3_key.bin file not found and unable to retrieve key from SDK files, you will be unable to resign packages.");
            if (!XvdFile.OdkKeyLoaded)
                Console.WriteLine("Warning: odk_key.bin file not found and unable to retrieve key from SDK files, you will be unable to decrypt XVDs.");
            if (!XvdFile.CikFileLoaded)
                Console.WriteLine("Warning: cik_keys.bin file not found and unable to retrieve key from SDK files, you will be unable to decrypt XVCs.");

            if (printHelp || (String.IsNullOrEmpty(fileList) && String.IsNullOrEmpty(folder) && extraArgs.Count <= 0))
            {
                if (!XvdFile.CikFileLoaded || !XvdFile.OdkKeyLoaded || !XvdFile.SignKeyLoaded)
                    Console.WriteLine();

                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(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(fmt + "-nn (-nonatives) - disable importing native windows functions (ncrypt etc)");
                Console.WriteLine(fmt + fmt +
                                  "note that signature verification/resigning won't work with this!");
                Console.WriteLine();
                Console.WriteLine(fmt + "-eu (-decrypt) = decrypt output xvd");
                Console.WriteLine(fmt + "-ee (-encrypt) [keyid] = encrypt output xvd");
                Console.WriteLine(fmt + fmt + "(optional [keyid] param for XVCs to choose which key inside cik_keys.bin to use)");
                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_key.bin 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 + "-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, doesn't seem to work properly with XVC packages yet (also removes NTFS compression from output VHD so Windows can mount it, use -nn to disable)");
                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(@"Note that to mount an XVD/XVC in Windows you'll have to decrypt it and remove the hash tables first (-eu -hd)");
                return;
            }

            Console.WriteLine();

            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;
            }

            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;
            }

            if (extraArgs.Count > 0)
            {
                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;
                    }
                    File.Copy(filePath, outputFile);
                    filePath = outputFile;
                }

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

                if (decryptPackage)
                {
                    if (!file.IsEncrypted)
                    {
                        Console.WriteLine(@"Error: package already decrypted");
                        return;
                    }
                    string keyToUse = "TestODK";
                    if (file.IsXvcFile)
                    {
                        byte[] outputKey;
                        keyToUse = file.GetXvcKey(0, out outputKey);
                        if (String.IsNullOrEmpty(keyToUse))
                        {
                            Console.WriteLine("Error: unable to find key for key GUID " +
                                              new Guid(file.XvcInfo.EncryptionKeyIds[0].KeyId));
                            return;
                        }
                    }
                    Console.WriteLine("Decrypting package using \"" + keyToUse + "\" key...");
                    bool success = file.Decrypt();
                    Console.WriteLine(success ? "Package decrypted successfully!" : "Error during decryption!");
                    if (!success)
                        return;
                }

                if (encryptPackage)
                {
                    if (file.IsEncrypted)
                    {
                        Console.WriteLine("Error: package already encrypted");
                        return;
                    }
                    string keyToUse = "ODK";
                    if (file.IsXvcFile)
                    {
                        var keyGuids = XvdFile.CikKeys.Keys.ToList();
                        if (encryptKeyId < 0 || encryptKeyId >= keyGuids.Count)
                        {
                            Console.WriteLine(
                                "Error: invalid key index \"" + encryptKeyId + "\" specified, make sure the index you provided exists inside cik_keys.bin!");
                            return;
                        }
                        keyToUse = keyGuids[encryptKeyId].ToString();
                    }
                    Console.WriteLine("Encrypting package using \"" + keyToUse + "\" key...");
                    bool success = file.Encrypt(encryptKeyId);
                    Console.WriteLine(success ? "Package encrypted successfully!" : "Error during encryption!");
                    if (!success)
                        return;
                }

                if (removeHashTree)
                {
                    if (!file.IsDataIntegrityEnabled)
                    {
                        Console.WriteLine("Error: cannot remove hash tree from package that hasn't got a hash tree.");
                        return;
                    }
                    Console.WriteLine("Attempting to remove hash tree from package...");
                    bool success = file.RemoveHashTree() && file.Save();
                    Console.WriteLine(success
                        ? "Hash tree removed successfully and header updated."
                        : "Error: hash tree is larger than input package (???)");
                    return;
                }

                if (addHashTree)
                {
                    if (file.IsDataIntegrityEnabled)
                    {
                        Console.WriteLine("Error: cannot add hash tree to package that already has a hash tree.");
                        return;
                    }
                    Console.WriteLine("Attempting to add hash tree to package...");
                    bool success = file.AddHashTree() && file.Save();
                    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;
                }

                if (rehashPackage)
                {
                    if (!file.IsDataIntegrityEnabled)
                    {
                        Console.WriteLine("Error: cannot rehash package that hasn't got a hash tree.");
                        return;
                    }
                    Console.WriteLine("Old top hash block hash: " + file.Header.TopHashBlockHash.ToHexString());
                    Console.WriteLine("Rehashing package...");
                    int[] fixedHashes = file.VerifyDataHashTree(true);
                    bool success = file.CalculateHashTree();
                    if (success)
                    {
                        Console.WriteLine("New top hash block hash: " + file.Header.TopHashBlockHash.ToHexString());
                        file.Save();
                    }

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

                if (resignPackage)
                {
                    if (!XvdFile.SignKeyLoaded)
                    {
                        Console.WriteLine("Error: rsa3_key.bin file was not found, unable to resign package without it.");
                        return;
                    }
                    bool success = file.Header.ResignWithSignKey();
                    Console.WriteLine(success
                        ? "Successfully resigned package."
                        : "Error: there was a problem resigning the package.");
                    if (!success)
                        return;
                }

                if (!String.IsNullOrEmpty(exvdDest))
                {
                    byte[] exvd = file.ExtractEmbeddedXvd();
                    if (exvd == null || exvd.Length <= 0)
                    {
                        Console.WriteLine("Error: no embedded XVD to extract.");
                        return;
                    }
                    try
                    {
                        File.WriteAllBytes(exvdDest, exvd);
                        Console.WriteLine(
                            "Extracted embedded XVD to \"" + exvdDest + "\" successfully (0x{0:X} bytes)", exvd.Length);
                    }
                    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("Error: no user data to extract.");
                        return;
                    }
                    try
                    {
                        File.WriteAllBytes(userDataDest, userData);
                        Console.WriteLine(
                            "Extracted XVD user data to \"" + userDataDest + "\" successfully (0x{0:X} bytes)",
                            userData.Length);
                    }
                    catch
                    {
                        Console.WriteLine("Error: failed to extract XVD user data.");
                    }
                }

                if (!String.IsNullOrEmpty(vhdDest))
                {
                    if (!file.IsEncrypted)
                    {
                        Console.WriteLine("Extracting XVD filesystem to VHD file \"" + vhdDest + "\"...");
                        bool success = file.ConvertToVhd(vhdDest);
                        Console.WriteLine(success
                            ? "Wrote VHD successfully."
                            : "Error: there was a problem extracting the filesystem from the XVD.");
                        if (!success)
                            return;
                    }
                    else
                    {
                        Console.WriteLine("Error: can't convert encrypted package to VHD.");
                    }
                }

                file.Dispose();
            }
        }
示例#2
0
 public XvdFilesystemStream(XvdFile file)
 {
     _xvdFile = file;
     Position = 0;
 }
示例#3
0
        const long CHUNK_SIZE = (16 * 1024 * 1024); // 16 MB

        public XvdFilesystem(XvdFile file)
        {
            _xvdFile = file;
            _fs      = new XvdFilesystemStream(_xvdFile);
        }