コード例 #1
0
        public void Parse(PatchCreatorOptions op)
        {
            var ark         = ArkFile.FromFile(op.InputPath);
            var inplaceEdit = string.IsNullOrWhiteSpace(op.OutputPath);

            var platformExt = GuessPlatform(op.InputPath);

            if (!inplaceEdit)
            {
                if ((int)ark.Version <= 3)
                {
                    // If ark version doesn't support multiple parts then copy entire ark to new directory
                    ark         = ark.CopyToDirectory(Path.Combine(op.OutputPath, "gen"));
                    inplaceEdit = true;
                }
                else
                {
                    // Add additional ark park
                    var patchPartName = $"{Path.GetFileNameWithoutExtension(op.InputPath)}_{ark.PartCount()}.ark";
                    var fullPartPath  = ((int)ark.Version < 9)
                        ? Path.Combine(op.OutputPath, "gen", patchPartName)
                        : Path.Combine(op.OutputPath, patchPartName);

                    ark.AddAdditionalPart(fullPartPath);
                }
            }

            var files = Directory.GetFiles(op.ArkFilesPath, "*", SearchOption.AllDirectories);

            // Open hashes
            var entryInfo = (string.IsNullOrWhiteSpace(op.HashesPath)
                ? new List <ArkEntryInfo>()
                : ArkEntryInfo.ReadFromCSV(op.HashesPath))
                            .ToDictionary(x => x.Path, y => y);

            var updatedHashes = new List <ArkEntryInfo>();

            var dtaRegex         = new Regex("(?i).dta$");
            var genPathedFile    = new Regex(@"(?i)gen[\/][^\/]+$");
            var dotRegex         = new Regex(@"\([.]+\)/");
            var forgeScriptRegex = new Regex("(?i).((dta)|(fusion)|(moggsong)|(script))$");

            // Create temp path
            var tempDir = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));

            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }

            foreach (var file in files)
            {
                var internalPath = FileHelper.GetRelativePath(file, op.ArkFilesPath)
                                   .Replace("\\", "/");

                string inputFilePath = file;

                if ((int)ark.Version < 7 && dtaRegex.IsMatch(internalPath))
                {
                    // Updates path
                    internalPath = $"{internalPath.Substring(0, internalPath.Length - 1)}b";

                    if (!genPathedFile.IsMatch(internalPath))
                    {
                        internalPath = internalPath.Insert(internalPath.LastIndexOf('/'), "/gen");
                    }

                    // Creates temp dtb file
                    inputFilePath = ScriptHelper.ConvertDtaToDtb(file, tempDir, ark.Encrypted, (int)ark.Version);
                }
                else if ((int)ark.Version >= 7 && forgeScriptRegex.IsMatch(internalPath))
                {
                    // Updates path
                    internalPath = $"{internalPath}_dta_{platformExt}";

                    // Creates temp dtb file
                    inputFilePath = ScriptHelper.ConvertDtaToDtb(file, tempDir, ark.Encrypted, (int)ark.Version);
                }

                if (dotRegex.IsMatch(internalPath))
                {
                    internalPath = dotRegex.Replace(internalPath, x => $"{x.Value.Substring(1, x.Length - 3)}/");
                }

                var fileName = Path.GetFileName(internalPath);
                var dirPath  = Path.GetDirectoryName(internalPath).Replace("\\", "/");

                var pendingEntry = new PendingArkEntry(fileName, dirPath)
                {
                    LocalFilePath = inputFilePath
                };

                ark.AddPendingEntry(pendingEntry);
                Console.WriteLine($"Added {pendingEntry.FullPath}");

                if (!entryInfo.TryGetValue(internalPath, out var hashInfo))
                {
                    continue;
                }

                // Update hash
                using var fs  = File.OpenRead(inputFilePath);
                hashInfo.Hash = Crypt.SHA1Hash(fs);
                updatedHashes.Add(hashInfo);
            }

            ark.CommitChanges(inplaceEdit);

            // Clean up temp files
            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }

            if (!inplaceEdit)
            {
                // Writes header
                var hdrPath = ((int)ark.Version < 9)
                    ? Path.Combine(op.OutputPath, "gen", Path.GetFileName(op.InputPath))
                    : Path.Combine(op.OutputPath, Path.GetFileName(op.InputPath));
                ark.WriteHeader(hdrPath);
            }
            else
            {
                // TODO: Also look at possibly still patching exe
                return;
            }

            // Copy exe
            var exePath = Path.Combine(op.OutputPath, Path.GetFileName(op.ExePath));

            File.Copy(op.ExePath, exePath, true);

            if (updatedHashes.Count <= 0)
            {
                return;
            }

            // Patch exe
            using var exeStream = File.OpenWrite(exePath);
            foreach (var hashInfo in updatedHashes)
            {
                var hashBytes = FileHelper.GetBytes(hashInfo.Hash);

                exeStream.Seek(hashInfo.Offset, SeekOrigin.Begin);
                exeStream.Write(hashBytes, 0, hashBytes.Length);

                Console.WriteLine($"Updated hash for {hashInfo.Path}");
            }
        }
コード例 #2
0
        public void Parse(HashFinderOptions op)
        {
            var watch = Stopwatch.StartNew();

            var ark  = ArkFile.FromFile(op.InputPath);
            var exts = new[] { "dtb", "elf", "mid" };

            var arkEntries = ark
                             .Entries
                             .Where(x => exts.Contains(x.Extension))
                             .ToList();

            var entryInfo = arkEntries
                            .Select(x => new ArkEntryInfo()
            {
                Path   = x.FullPath,
                Hash   = "",
                Offset = -1
            })
                            .ToList();

            var i = 0;

            foreach (var dtb in arkEntries)
            {
                using (var dtbStream = ark.GetArkEntryFileStream(dtb))
                {
                    entryInfo[i].Hash = Crypt.SHA1Hash(dtbStream);
                    i++;
                }
            }

            var exeBytes = File.ReadAllBytes(op.ExePath);

            Parallel.ForEach(entryInfo, (info) =>
            {
                using (var ar = new AwesomeReader(new MemoryStream(exeBytes)))
                {
                    var hashBytes = FileHelper.GetBytes(info.Hash);
                    ar.BaseStream.Seek(0, SeekOrigin.Begin);

                    var offset = ar.FindNext(hashBytes);
                    if (offset != -1)
                    {
                        info.Offset = offset;
                    }
                }
            });

            watch.Stop();

            var protectedInfo = entryInfo
                                .Where(x => x.Offset != -1)
                                .OrderBy(x => x.Path)
                                .ToList();

            ArkEntryInfo.WriteToCSV(protectedInfo, op.HashesPath);
            var hashCount = protectedInfo.Count();

            Console.WriteLine($"Found offsets for {hashCount} entries of out {entryInfo.Count}");
            Console.WriteLine($"Scan took {watch.Elapsed} ({watch.ElapsedMilliseconds}ms)");
        }