private static string findOnly(string file, ref string[] svals) { byte[] bytes; bytes = File.ReadAllBytes(file); int[] locs = Patcher.BinaryPatternSearch(ref bytes, svals, false); if (locs.Length == 1) { return(string.Format("Pattern found at: {0}+{1:X8}", tarfilename, locs[0])); } else if (locs.Length < 1) { return("Pattern not found."); } else { return(locs.Length.ToString() + " occurrences found."); } }
private static bool doMemPatch(string[] processName, string[] svals, int offset, string[] rvals) { // Get process Process proc; if (processName.Length == 3) { proc = Process.GetProcessById(int.Parse(processName[2])); } else { proc = Process.GetProcessesByName(processName[1])[0]; } IntPtr baseAddress = proc.MainModule.BaseAddress; IntPtr moduleSize = (IntPtr)proc.MainModule.ModuleMemorySize; IntPtr hProc = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.All, false, proc.Id); // Read bytes int bytesRead = 0; byte[] bytes = new byte[moduleSize.ToInt32()]; if (!NativeMethods.ReadProcessMemory(hProc, baseAddress, bytes, moduleSize, ref bytesRead) || bytes == null) { goto badEnding; } // Search binary data for pattern int[] locs = Patcher.BinaryPatternSearch(ref bytes, svals); // Make sure we only have 1 match if (!onlyOne(locs.Length, processName[1], String.Join(" ", svals))) { goto badEnding; } // Replace int replaced = Patcher.BinaryPatternReplace(ref bytes, locs[0], rvals, offset); if (replaced < 1) { goto badEnding; } // Write bytes int bytesWritten = 0; uint oldp = 0; uint oldp2 = 0; byte[] newbytes = new byte[rvals.Length]; IntPtr off = baseAddress + locs[0] + offset; // Get write privileges if (!NativeMethods.VirtualProtectEx(proc.Handle, off, (IntPtr)rvals.Length, (uint)NativeMethods.Protection.PAGE_EXECUTE_WRITECOPY, ref oldp)) { goto badEnding; } // Do actual write Array.Copy(bytes, locs[0] + offset, newbytes, 0, rvals.Length); NativeMethods.WriteProcessMemory(hProc, off, newbytes, (IntPtr)rvals.Length, ref bytesWritten); // Set original access rights back (we have no buisness getting errors here) NativeMethods.VirtualProtectEx(proc.Handle, off, (IntPtr)rvals.Length, oldp, ref oldp2); // Were we successful? if (bytesWritten != rvals.Length) { goto badEnding; } // Happy ending. :) NativeMethods.CloseHandle(hProc); return(true); badEnding: NativeMethods.CloseHandle(hProc); return(false); }
private static bool doPatch(string file, string search, string offset, string replace) { // Variable setup int off; if (!Int32.TryParse(offset, out off)) { return(false); } search = search.Trim(); replace = replace.Trim(); string[] svals = search.Replace(_qq, _q).Replace(_ss, _q).Split(' '); string[] rvals = replace.Replace(_qq, _q).Replace(_ss, _q).Split(' '); if (replace.Length == 0) { return(findOnly(file, ref svals)); } // MemPatch! :) (Highly experimental!) if (file.Length > 5 && file.Substring(0, 5).ToLower() == _p) { return(doMemPatch(file.Split(':'), svals, off, rvals)); } if (!File.Exists(file)) { if (isconsole == 0) { MessageBox.Show("File not found."); } else if (isconsole == 2) { Console.WriteLine(file + " not found."); } return(false); } // Get file contents byte[] bytes = File.ReadAllBytes(file); // Search binary data for pattern int[] locs = Patcher.BinaryPatternSearch(ref bytes, svals); // Make sure we only have 1 match if (!onlyOne(locs.Length, file, search)) { return(false); } // Replace int replaced = Patcher.BinaryPatternReplace(ref bytes, locs[0], rvals, off); if (replaced < 1) { return(false); } // Write new file if (!File.Exists(file + _b)) { File.Move(file, file + _b); } File.WriteAllBytes(file, bytes); return(true); }
private static string processArgs() { int patched = 0; string ret = " "; switch (args[1]) { case "e": case "-e": case "/e": for (int i = 0; i < settings.Count; i++) { if (doPatch(settings[i][1], settings[i][2], settings[i][3], settings[i][4])) { patched++; } else if (isconsole == 2) { Console.WriteLine(settings[i][0] + " patch failed. (Nothing written.)"); } } break; case "x": case "-x": case "/x": if (args.Length != 6) { goto default; } if (doPatch(args[2], args[3], args[4], args[5])) { return("All done. " + args[2] + " successfully patched.\n"); } break; case "r": case "-r": case "/r": for (int i = 0; i < settings.Count; i++) { restore(settings[i][1]); } break; case "m": case "-m": case "/m": if (args.Length != 5) { goto default; } if (!File.Exists(args[3]) || !File.Exists(args[4])) { break; } if ((new FileInfo(args[3])).Length != (new FileInfo(args[4])).Length) { if (isconsole == 2) { Console.WriteLine("Not equal size!"); } break; } Spinner.Start(); byte[] bytes1 = File.ReadAllBytes(args[3]); byte[] bytes2 = File.ReadAllBytes(args[4]); if (args[2].Length > gz.Length && args[2].Substring(args[2].Length - gz.Length) == gz) { CompressINI(args[2], Patcher.Format4Ini(Patcher.FindDiffs(ref bytes1, ref bytes2), args[3], "Patch")); } else { File.WriteAllText(args[2], Patcher.Format4Ini(Patcher.FindDiffs(ref bytes1, ref bytes2), args[3], "Patch")); } Spinner.Stop(); ret = args[2] + " written.\n"; break; default: return("Command line options:\n\n" + iam + " [e [ini_file]]\n" + "\tRun all patches specified in the inifile.\n\n" + iam + " [x file search_pattern offset replace_pattern]\n" + "\tRun patch given by arguments.\n\n" + iam + " [r [ini_file]]\n" + "\tRestore all files mentioned in inifile from their backups.\n\n" + iam + " [m out_ini_file[" + gz + "] original_file changed_file]\n" + "\tTry to create a pattern based patch for original_file. (Don't get your hopes up.)\n"); } if (patched > 0) { ret = "All done. " + patched.ToString() + " patches executed.\n"; } return(ret); }