internal void Restore(string PatchDefinition) { List <FilePatcher> LoadedFiles = new List <FilePatcher>(); try { // Find a matching TargetVersion PatchDefinition Definition = PatchDefinitions.Single(d => string.Compare(d.Name, PatchDefinition, true) == 0); TargetVersion MatchedVersion = null; foreach (TargetVersion CurrentVersion in Definition.TargetVersions) { bool Match = true; foreach (TargetFile CurrentTargetFile in CurrentVersion.TargetFiles) { // Determine target path string TargetPath = null; foreach (TargetRedirection CurrentRedirection in TargetRedirections) { if (CurrentTargetFile.Path.StartsWith(CurrentRedirection.RelativePath, StringComparison.OrdinalIgnoreCase)) { TargetPath = Path.Combine(CurrentRedirection.TargetPath, CurrentTargetFile.Path); break; } } if (TargetPath == null) { TargetPath = Path.Combine(this.TargetPath, CurrentTargetFile.Path); } // Lookup file FilePatcher CurrentFile = LoadedFiles.SingleOrDefault(f => string.Compare(f.FilePath, TargetPath, true) == 0); if (CurrentFile == null) { CurrentFile = new FilePatcher(TargetPath); LoadedFiles.Add(CurrentFile); } // Compare hash if (!StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentTargetFile.HashOriginal) && !StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentTargetFile.HashPatched)) { Match = false; foreach (TargetFile CurrentObsoleteFile in CurrentTargetFile.Obsolete) { if (StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentObsoleteFile.HashPatched)) { Match = true; // Found match after all. File is patched with an obsolete version of this patch. break; } } if (!Match) { break; } } } if (Match) { MatchedVersion = CurrentVersion; break; } } if (MatchedVersion != null) { foreach (TargetFile CurrentTargetFile in MatchedVersion.TargetFiles) { FilePatcher CurrentFile = LoadedFiles.SingleOrDefault(f => string.Compare(f.FilePath, Path.Combine(TargetPath, CurrentTargetFile.Path), true) == 0); if (!StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentTargetFile.HashOriginal)) { CurrentFile.StartPatching(); if (StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentTargetFile.HashPatched)) { foreach (Patch CurrentPatch in CurrentTargetFile.Patches) { CurrentFile.ApplyPatch(CurrentPatch.Address, CurrentPatch.OriginalBytes); } } else { foreach (TargetFile CurrentObsoleteFile in CurrentTargetFile.Obsolete) { if (StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentObsoleteFile.HashPatched)) { foreach (Patch CurrentPatch in CurrentObsoleteFile.Patches) { CurrentFile.ApplyPatch(CurrentPatch.Address, CurrentPatch.OriginalBytes); } break; } } } CurrentFile.FinishPatching(); } } } } catch (Exception Ex) { LogFile.LogException(Ex); } }
internal bool Patch(string PatchDefinition) { bool Result = false; List <FilePatcher> LoadedFiles = new List <FilePatcher>(); LogFile.Log("Attempt patch: " + PatchDefinition); // Find a matching TargetVersion PatchDefinition Definition = PatchDefinitions.Single(d => string.Compare(d.Name, PatchDefinition, true) == 0); TargetVersion MatchedVersion = null; int VersionIndex = 0; foreach (TargetVersion CurrentVersion in Definition.TargetVersions) { bool Match = true; int FileIndex = 0; foreach (TargetFile CurrentTargetFile in CurrentVersion.TargetFiles) { // Determine target path string TargetPath = null; foreach (TargetRedirection CurrentRedirection in TargetRedirections) { if (CurrentTargetFile.Path.StartsWith(CurrentRedirection.RelativePath, StringComparison.OrdinalIgnoreCase)) { TargetPath = Path.Combine(CurrentRedirection.TargetPath + "\\", CurrentTargetFile.Path); break; } } if (TargetPath == null) { TargetPath = Path.Combine(this.TargetPath + "\\", CurrentTargetFile.Path); } // Lookup file FilePatcher CurrentFile = LoadedFiles.SingleOrDefault(f => string.Compare(f.FilePath, TargetPath, true) == 0); if (CurrentFile == null) { if ((TargetImage != null) && (!TargetPath.Contains(':'))) { CurrentFile = new FilePatcher(TargetPath, TargetImage.OpenFile(TargetPath, FileMode.Open, FileAccess.ReadWrite)); } else { CurrentFile = new FilePatcher(TargetPath); } LoadedFiles.Add(CurrentFile); } // Compare hash if (!StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentTargetFile.HashOriginal) && !StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentTargetFile.HashPatched)) { Match = false; foreach (TargetFile CurrentObsoleteFile in CurrentTargetFile.Obsolete) { if (StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentObsoleteFile.HashPatched)) { Match = true; // Found match after all. File is patched with an obsolete version of this patch. break; } } if (!Match) { LogFile.Log("Pattern: " + VersionIndex.ToString() + ", " + FileIndex.ToString()); break; } } FileIndex++; } if (Match) { MatchedVersion = CurrentVersion; break; } VersionIndex++; } if (MatchedVersion != null) { LogFile.Log("Apply: " + MatchedVersion.Description); foreach (TargetFile CurrentTargetFile in MatchedVersion.TargetFiles) { FilePatcher CurrentFile = LoadedFiles.SingleOrDefault(f => string.Compare(f.FilePath, Path.Combine(TargetPath + "\\", CurrentTargetFile.Path), true) == 0); if (!StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentTargetFile.HashPatched)) { CurrentFile.StartPatching(); if (!StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentTargetFile.HashOriginal)) { // File is already patched, but with an older version of this patch. // First unpatch back to original. foreach (TargetFile CurrentObsoleteFile in CurrentTargetFile.Obsolete) { if (StructuralComparisons.StructuralEqualityComparer.Equals(CurrentFile.Hash, CurrentObsoleteFile.HashPatched)) { foreach (Patch CurrentPatch in CurrentObsoleteFile.Patches) { CurrentFile.ApplyPatch(CurrentPatch.Address, CurrentPatch.OriginalBytes); } break; } } } foreach (Patch CurrentPatch in CurrentTargetFile.Patches) { CurrentFile.ApplyPatch(CurrentPatch.Address, CurrentPatch.PatchedBytes); } CurrentFile.FinishPatching(); } } Result = true; } return(Result); }