Esempio n. 1
0
        private static void PatchTest()
        {
            var targetPath = @"..\..\..\Patchwork.Tests.Target\bin\debug\Patchwork.Tests.Target.dll";;

            var dir = Path.GetDirectoryName(targetPath);
            var fn = Path.GetFileNameWithoutExtension(targetPath);
            var ext = Path.GetExtension(targetPath);
            var newFileName = string.Format("{0}.patched{1}", fn, ext);
            var newTarget = Path.Combine(dir, newFileName);
            File.Copy(targetPath, newTarget, true);
            var patcher = new AssemblyPatcher(newTarget, log: Log);
            var patchPath = typeof(Patchwork.Tests.Patch.TestClass).Assembly.Location;
            var maker = new ManifestCreator();
            var manifest = maker.CreateManifest(patchPath);
            patcher.PatchManifest(manifest, null);

            patcher.WriteTo(newTarget);
            Log.Information("Loading assembly into memory...");
            var loaded = Assembly.LoadFrom(newTarget);
            Log.Information("Invoking method");
            var module = loaded.GetModules()[0];
            var types = module.FindTypes((typ, o) => typ.Name.Contains("EntryPoint"), null);
            var foundType = types.Single();
            var method = foundType.GetMethod("StandardTests");
            try
            {
                var ret = method.Invoke(null, null);
                Log.Information("Result: {@Result}", ret);
            }
            catch (TargetInvocationException ex)
            {
                throw ex.InnerException;
            }
            Console.ReadKey();
        }
Esempio n. 2
0
		public static int Main(string[] args)
		{
			bool interactive = args.Length > 0;

			gendiffs = args.Any(arg => arg == "--generatediffs" || arg == "-gd");

			string logfile = (from arg in args
							  where arg.StartsWith("--logFile:", StringComparison.Ordinal) || arg.StartsWith("-l:", StringComparison.Ordinal)
							  select arg.Split(':').Last()).FirstOrDefault();

			LogFile = !String.IsNullOrEmpty(logfile) ? logfile : LogFile;

			LogToFile = !String.IsNullOrEmpty(logfile);

			if (gendiffs)
				MethodDB.GetInstance();

			newAssCS = true;

			Log($"[( Pluton Patcher v{Version} )]");

			rustAssembly = AssemblyPatcher.GetPatcher("Assembly-CSharp.dll");

			if (rustAssembly.GetType("PlutonPatched") != null) {
				LogError("Assembly-CSharp.dll is already patched!");
				if (interactive)
					System.Threading.Thread.Sleep(250);
				return (int)ExitCode.ACDLL_ALREADY_PATCHED;
			}

			foreach (var json in Directory.GetFiles("./", "*.json")) {
				JSON.Array jsonArr = JSON.Array.Parse(File.ReadAllText(json));
				foreach (JSON.Value jsonElmnt in jsonArr) {
					JSON.Object jsonObj = jsonElmnt.Obj;
					var assemblyPatch = AssemblyPatch.ParseFromJSON(jsonObj);
					if (!assemblyPatch.Patch()) {
						LogError("Failed to patch!");
						if (interactive)
							System.Threading.Thread.Sleep(250);
						return (int)ExitCode.ACDLL_GENERIC_PATCH_ERR;
					}
				}
			}

			if (gendiffs) {
				MethodDB.GetInstance().Save();

				string diffs = MethodDB.GetDifferences();

				if (!String.IsNullOrEmpty(diffs))
					File.WriteAllText($"diffs-{DateTime.Now.ToShortDateString()}{DateTime.Now.ToShortTimeString()}.html".Replace('\\', '_').Replace('/', '_'), "<html><head><style>del,ins{text-decoration:none}ins{background-color:#0F0}del{color:#999;background-color:#F00}</style></head><body>" + diffs + "</body></html>");
			}

			Log("Completed!");

			if (interactive)
				System.Threading.Thread.Sleep(250);

			return (int)ExitCode.SUCCESS;
		}
Esempio n. 3
0
        private static void PatchTest()
        {
            var targetPath = @"..\..\..\Patchwork.Tests.Target\bin\debug\Patchwork.Tests.Target.dll";;

            var dir = Path.GetDirectoryName(targetPath);
            var fn = Path.GetFileNameWithoutExtension(targetPath);
            var ext = Path.GetExtension(targetPath);
            var newFileName = string.Format("{0}.patched{1}", fn, ext);
            var newTarget = Path.Combine(dir, newFileName);
            File.Copy(targetPath, newTarget, true);
            var patcher = new AssemblyPatcher(newTarget, log: Log);
            var patchPath = typeof(Patchwork.Tests.Patch.TestClass).Assembly.Location;
            patcher.DebugOptions = DebugFlags.CreationOverwrites;
            patcher.PatchAssembly(patchPath);

            patcher.WriteTo(newTarget);
            Log.Information("Loading assembly into memory...");
            var loaded = Assembly.LoadFrom(newTarget);
            Log.Information("Invoking method");
            var module = loaded.GetModules()[0];
            var types = module.FindTypes((typ, o) => typ.Name.Contains("EntryPoint"), null);
            var foundType = types.Single();
            var method = foundType.GetMethod("StandardTests");
            Process.Start(@"C:\Users\lifeg_000\AppData\Local\Microsoft\VisualStudio\12.0\Extensions\bicaz2ty.1dn\ILSpy.exe", string.Format("\"{0}\"", newTarget));
            try
            {
                var ret = method.Invoke(null, null);
                Log.Information("Result: {@Result}", ret);
            }
            catch (TargetInvocationException ex)
            {
                throw ex.InnerException;
            }
            Console.ReadKey();
        }
Esempio n. 4
0
        public static void Run()
        {
            try
            {
                AllocateConsole();

                if (ConfigApplyRuntimePatches.Value)
                {
                    UnityPatches.Apply();
                }

                Logger.Sources.Add(TraceLogSource.CreateSource());

                PreloaderLog = new PreloaderConsoleListener(ConfigPreloaderCOutLogging.Value);

                Logger.Listeners.Add(PreloaderLog);


                string consoleTile = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Process.GetCurrentProcess().ProcessName}";

                ConsoleWindow.Title = consoleTile;
                Logger.LogMessage(consoleTile);

                //See BuildInfoAttribute for more information about this section.
                object[] attributes = typeof(BuildInfoAttribute).Assembly.GetCustomAttributes(typeof(BuildInfoAttribute), false);

                if (attributes.Length > 0)
                {
                    var attribute = (BuildInfoAttribute)attributes[0];

                    Logger.LogMessage(attribute.Info);
                }

#if UNITY_2018
                Logger.LogMessage("Compiled in Unity v2018 mode");
#else
                Logger.LogMessage("Compiled in Legacy Unity mode");
#endif

                Logger.LogInfo($"Running under Unity v{Process.GetCurrentProcess().MainModule.FileVersionInfo.FileVersion}");

                Logger.LogMessage("Preloader started");


                AssemblyPatcher.AddPatcher(new PatcherPlugin
                {
                    TargetDLLs = new[] { ConfigEntrypointAssembly.Value },
                    Patcher    = PatchEntrypoint,
                    Name       = "BepInEx.Chainloader"
                });

                AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath, GetPatcherMethods);

                Logger.LogInfo($"{AssemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");


                AssemblyPatcher.PatchAndLoad(Paths.ManagedPath);


                AssemblyPatcher.DisposePatchers();


                Logger.LogMessage("Preloader finished");

                Logger.Listeners.Remove(PreloaderLog);
                Logger.Listeners.Add(new ConsoleLogListener());

                PreloaderLog.Dispose();
            }
            catch (Exception ex)
            {
                try
                {
                    Logger.LogFatal("Could not run preloader!");
                    Logger.LogFatal(ex);

                    PreloaderLog?.Dispose();

                    if (!ConsoleWindow.IsAttached)
                    {
                        //if we've already attached the console, then the log will already be written to the console
                        AllocateConsole();
                        Console.Write(PreloaderLog);
                    }

                    PreloaderLog = null;
                }
                finally
                {
                    File.WriteAllText(
                        Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"),
                        PreloaderLog + "\r\n" + ex);

                    PreloaderLog?.Dispose();
                    PreloaderLog = null;
                }
            }
        }
Esempio n. 5
0
        public static void Run()
        {
            try
            {
                ConsoleManager.Initialize(false);

                PreloaderLog = new PreloaderConsoleListener();
                Logger.Listeners.Add(PreloaderLog);


                if (ConsoleManager.ConfigConsoleEnabled.Value)
                {
                    ConsoleManager.CreateConsole();
                    Logger.Listeners.Add(new ConsoleLogListener());
                }

                ChainloaderLogHelper.PrintLogInfo(Log);

                Log.LogInfo($"Running under Unity v{FileVersionInfo.GetVersionInfo(Paths.ExecutablePath).FileVersion}");

                Log.LogDebug($"Game executable path: {Paths.ExecutablePath}");
                Log.LogDebug($"Unhollowed assembly directory: {IL2CPPUnhollowedPath}");
                Log.LogDebug($"BepInEx root path: {Paths.BepInExRootPath}");


                UnhollowerLog              = Logger.CreateLogSource("Unhollower");
                LogSupport.InfoHandler    += UnhollowerLog.LogInfo;
                LogSupport.WarningHandler += UnhollowerLog.LogWarning;
                LogSupport.TraceHandler   += UnhollowerLog.LogDebug;
                LogSupport.ErrorHandler   += UnhollowerLog.LogError;


                if (ProxyAssemblyGenerator.CheckIfGenerationRequired())
                {
                    ProxyAssemblyGenerator.GenerateAssemblies();
                }


                using (var assemblyPatcher = new AssemblyPatcher())
                {
                    assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                    Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} patcher plugin{(assemblyPatcher.PatcherPlugins.Count == 1 ? "" : "s")} loaded");

                    assemblyPatcher.LoadAssemblyDirectories(IL2CPPUnhollowedPath);

                    Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} assemblies discovered");

                    assemblyPatcher.PatchAndLoad();
                }


                Logger.Listeners.Remove(PreloaderLog);


                Chainloader = new IL2CPPChainloader();

                Chainloader.Initialize();
            }
            catch (Exception ex)
            {
                Log.LogFatal(ex);

                throw;
            }
        }
Esempio n. 6
0
        private void ApplyInstructions(IEnumerable <PatchGroup> patchGroups, ProgressObject po)
        {
            //TODO: Use a different progress tracking system and make the entire patching operation more recoverable and fault-tolerant.
            //TODO: Refactor this method.
            patchGroups = patchGroups.ToList();
            var appInfo      = AppInfo;
            var logger       = Logger;
            var fileProgress = new ProgressObject();

            po.Child.Value = fileProgress;
            var patchProgress = new ProgressObject();

            fileProgress.Child.Value = patchProgress;
            var myAttributesAssembly   = typeof(AppInfo).Assembly;
            var attributesAssemblyName = Path.GetFileName(myAttributesAssembly.Location);
            var history = new List <XmlFileHistory>();

            po.TaskTitle.Value = "Patching Game";
            po.TaskText.Value  = appInfo.AppName;
            po.Total.Value     = patchGroups.Count();

            foreach (var patchGroup in patchGroups)
            {
                var patchCount = patchGroup.Instructions.Count;
                po.TaskTitle.Value = $"Patching {appInfo.AppName}";
                var targetFile = patchGroup.TargetPath;
                po.TaskText.Value = Path.GetFileName(targetFile);
                //Note that Path.Combine(FILENAME, "..", OTHER_FILENAME) doesn't work on Mono but does work on .NET.
                var dir = Path.GetDirectoryName(targetFile);

                var localAssemblyName = Path.Combine(dir, attributesAssemblyName);
                var copy = true;
                fileProgress.TaskTitle.Value = "Patching File";
                fileProgress.Total.Value     = 2 + patchCount;
                fileProgress.Current.Value++;

                var backupModified = PatchingHelper.GetBackupForModified(targetFile);
                var backupOrig     = PatchingHelper.GetBackupForOriginal(targetFile);
                fileProgress.TaskText.Value = "Applying Patch";

                if (!PatchingHelper.DoesFileMatchPatchList(backupModified, targetFile, patchGroup.Instructions) ||
                    Preferences.AlwaysPatch)
                {
                    if (File.Exists(localAssemblyName))
                    {
                        try {
                            var localAssembly = AssemblyCache.Default.ReadAssembly(localAssemblyName);
                            if (localAssembly.GetAssemblyMetadataString() == myAttributesAssembly.GetAssemblyMetadataString())
                            {
                                copy = false;
                            }
                        }
                        catch (Exception ex) {
                            Logger.Warning(ex, $"Failed to read local attributes assembly so it will be overwritten.");
                            //if reading the assembly failed for any reason, just ignore...
                        }
                    }
                    if (copy)
                    {
                        File.Copy(myAttributesAssembly.Location, localAssemblyName, true);
                    }

                    var patcher = new AssemblyPatcher(targetFile, logger)
                    {
                        EmbedHistory = true
                    };

                    foreach (var patch in patchGroup.Instructions)
                    {
                        try {
                            patcher.PatchManifest(patch.Patch, patchProgress.ToMonitor());
                        }
                        catch (PatchException ex) {
                            throw new PatchingProcessException(ex)
                                  {
                                      AssociatedInstruction = patch,
                                      AssociatedPatchGroup  = patchGroup,
                                      Step = PatchProcessingStep.ApplyingSpecificPatch
                                  };
                        }
                        fileProgress.Current.Value++;
                    }
                    patchProgress.TaskText.Value  = "";
                    patchProgress.TaskTitle.Value = "";


                    fileProgress.Current.Value++;
                    fileProgress.TaskText.Value = "Writing Assembly";
                    if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                    {
                        fileProgress.TaskText.Value = "Running PEVerify...";
                        var targetFolder = Path.GetDirectoryName(targetFile);
                        try {
                            var peOutput = patcher.RunPeVerify(new PEVerifyInput {
                                AssemblyResolutionFolder = targetFolder,
                                IgnoreErrors             = AppInfo.IgnorePEVerifyErrors.ToList()
                            });
                            logger.Information(peOutput.Output);
                        }
                        catch (Exception ex) {
                            logger.Error(ex, "Failed to run PEVerify on the assembly.");
                        }
                    }

                    try {
                        patcher.WriteTo(backupModified);
                    }
                    catch (Exception ex) {
                        throw new PatchingProcessException(ex)
                              {
                                  AssociatedInstruction = null,
                                  AssociatedPatchGroup  = patchGroup,
                                  Step = PatchProcessingStep.WritingToFile
                              };
                    }
                }
                else
                {
                    fileProgress.Current.Value += patchCount;
                }
                try {
                    PatchingHelper.SwitchFilesSafely(backupModified, targetFile, backupOrig);
                }
                catch (Exception ex) {
                    throw new PatchingProcessException(ex)
                          {
                              AssociatedInstruction = null,
                              AssociatedPatchGroup  = patchGroup,
                              Step = PatchProcessingStep.PerformingSwitch
                          };
                }
                AssemblyCache.Default.ClearCache();
                po.Current.Value++;
            }
        }
Esempio n. 7
0
        public static void Run()
        {
            try
            {
                AllocateConsole();

                bool bridgeInitialized = Utility.TryDo(() =>
                {
                    if (ConfigShimHarmony.Value)
                    {
                        HarmonyDetourBridge.Init();
                    }
                }, out var harmonyBridgeException);

                Exception runtimePatchException = null;
                if (bridgeInitialized)
                {
                    Utility.TryDo(() =>
                    {
                        if (ConfigApplyRuntimePatches.Value)
                        {
                            UnityPatches.Apply();
                        }
                    }, out runtimePatchException);
                }

                Logger.Sources.Add(TraceLogSource.CreateSource());

                PreloaderLog = new PreloaderConsoleListener(ConfigPreloaderCOutLogging.Value);
                Logger.Listeners.Add(PreloaderLog);

                string consoleTile = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Process.GetCurrentProcess().ProcessName}";
                ConsoleWindow.Title = consoleTile;
                Logger.LogMessage(consoleTile);

                //See BuildInfoAttribute for more information about this section.
                object[] attributes = typeof(BuildInfoAttribute).Assembly.GetCustomAttributes(typeof(BuildInfoAttribute), false);

                if (attributes.Length > 0)
                {
                    var attribute = (BuildInfoAttribute)attributes[0];
                    Logger.LogMessage(attribute.Info);
                }

                Logger.LogInfo($"Running under Unity v{FileVersionInfo.GetVersionInfo(Paths.ExecutablePath).FileVersion}");
                Logger.LogInfo($"CLR runtime version: {Environment.Version}");
                Logger.LogInfo($"Supports SRE: {Utility.CLRSupportsDynamicAssemblies}");

                if (harmonyBridgeException != null)
                {
                    Logger.LogWarning($"Failed to enable fix for Harmony for .NET Standard API. Error message: {harmonyBridgeException.Message}");
                }

                if (runtimePatchException != null)
                {
                    Logger.LogWarning($"Failed to apply runtime patches for Mono. See more info in the output log. Error message: {runtimePatchException.Message}");
                }

                Logger.LogMessage("Preloader started");

                AssemblyPatcher.AddPatcher(new PatcherPlugin
                {
                    TargetDLLs = () => new[] { ConfigEntrypointAssembly.Value },
                    Patcher    = PatchEntrypoint,
                    TypeName   = "BepInEx.Chainloader"
                });

                AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                Logger.LogInfo($"{AssemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");

                AssemblyPatcher.PatchAndLoad(Paths.ManagedPath);
                AssemblyPatcher.DisposePatchers();


                Logger.LogMessage("Preloader finished");

                Logger.Listeners.Remove(PreloaderLog);
                Logger.Listeners.Add(new ConsoleLogListener());

                PreloaderLog.Dispose();
            }
            catch (Exception ex)
            {
                File.WriteAllText("err.log", ex.ToString());
                try
                {
                    Logger.LogFatal("Could not run preloader!");
                    Logger.LogFatal(ex);

                    PreloaderLog?.Dispose();

                    if (!ConsoleWindow.IsAttached)
                    {
                        //if we've already attached the console, then the log will already be written to the console
                        AllocateConsole();
                        Console.Write(PreloaderLog);
                    }

                    PreloaderLog = null;
                }
                finally
                {
                    File.WriteAllText(
                        Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"),
                        PreloaderLog + "\r\n" + ex);

                    PreloaderLog?.Dispose();
                    PreloaderLog = null;
                }
            }
        }
Esempio n. 8
0
        public static void Run()
        {
            try
            {
                InitializeHarmony();

                ConsoleManager.Initialize(false);
                AllocateConsole();

                Utility.TryDo(() =>
                {
                    if (ConfigApplyRuntimePatches.Value)
                    {
                        UnityPatches.Apply();
                    }
                }, out var runtimePatchException);

                Logger.InitializeInternalLoggers();
                Logger.Sources.Add(TraceLogSource.CreateSource());

                PreloaderLog = new PreloaderConsoleListener();
                Logger.Listeners.Add(PreloaderLog);

                string consoleTile = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Paths.ProcessName}";

                if (ConsoleManager.ConsoleActive)
                {
                    ConsoleManager.SetConsoleTitle(consoleTile);
                }

                Logger.LogMessage(consoleTile);

                //See BuildInfoAttribute for more information about this section.
                object[] attributes = typeof(BuildInfoAttribute).Assembly.GetCustomAttributes(typeof(BuildInfoAttribute), false);

                if (attributes.Length > 0)
                {
                    var attribute = (BuildInfoAttribute)attributes[0];
                    Logger.LogMessage(attribute.Info);
                }

                Logger.LogInfo($"Running under Unity v{GetUnityVersion()}");
                Logger.LogInfo($"CLR runtime version: {Environment.Version}");
                Logger.LogInfo($"Supports SRE: {Utility.CLRSupportsDynamicAssemblies}");

                if (runtimePatchException != null)
                {
                    Logger.LogWarning($"Failed to apply runtime patches for Mono. See more info in the output log. Error message: {runtimePatchException.Message}");
                }

                Logger.LogMessage("Preloader started");

                AssemblyPatcher.AddPatcher(new PatcherPlugin
                {
                    TargetDLLs = () => new[] { ConfigEntrypointAssembly.Value },
                    Patcher    = PatchEntrypoint,
                    TypeName   = "BepInEx.Chainloader"
                });

                AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                Logger.LogInfo($"{AssemblyPatcher.PatcherPlugins.Count} patcher plugin{(AssemblyPatcher.PatcherPlugins.Count == 1 ? "" : "s")} loaded");

                AssemblyPatcher.PatchAndLoad(Paths.ManagedPath);
                AssemblyPatcher.DisposePatchers();

                Logger.LogMessage("Preloader finished");

                Logger.Listeners.Remove(PreloaderLog);

                PreloaderLog.Dispose();
            }
            catch (Exception ex)
            {
                try
                {
                    Logger.LogFatal("Could not run preloader!");
                    Logger.LogFatal(ex);

                    if (!ConsoleManager.ConsoleActive)
                    {
                        //if we've already attached the console, then the log will already be written to the console
                        AllocateConsole();
                        Console.Write(PreloaderLog);
                    }
                }
                catch { }

                string log = string.Empty;

                try
                {
                    // We could use platform-dependent newlines, however the developers use Windows so this will be easier to read :)

                    log  = string.Join("\r\n", PreloaderConsoleListener.LogEvents.Select(x => x.ToString()).ToArray());
                    log += "\r\n";

                    PreloaderLog?.Dispose();
                    PreloaderLog = null;
                }
                catch { }

                File.WriteAllText(
                    Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"),
                    log + ex);
            }
        }
Esempio n. 9
0
        public static void Run()
        {
            try
            {
                InitializeHarmony();

                ConsoleManager.Initialize(false);
                AllocateConsole();

                Utility.TryDo(() =>
                {
                    if (ConfigApplyRuntimePatches.Value)
                    {
                        UnityPatches.Apply();
                    }
                }, out var runtimePatchException);

                Logger.Sources.Add(new HarmonyLogSource());
                Logger.Sources.Add(TraceLogSource.CreateSource());

                Logger.Listeners.Add(new ConsoleLogListener());
                PreloaderLog = new PreloaderConsoleListener();
                Logger.Listeners.Add(PreloaderLog);

                ChainloaderLogHelper.PrintLogInfo(Log);

                Log.LogInfo($"Running under Unity v{GetUnityVersion()}");
                Log.LogInfo($"CLR runtime version: {Environment.Version}");
                Log.LogInfo($"Supports SRE: {Utility.CLRSupportsDynamicAssemblies}");

                Log.LogDebug($"Game executable path: {Paths.ExecutablePath}");
                Log.LogDebug($"Unity Managed directory: {Paths.ManagedPath}");
                Log.LogDebug($"BepInEx root path: {Paths.BepInExRootPath}");

                if (runtimePatchException != null)
                {
                    Log.LogWarning($"Failed to apply runtime patches for Mono. See more info in the output log. Error message: {runtimePatchException.Message}");
                }

                Log.LogMessage("Preloader started");

                TypeLoader.SearchDirectories.UnionWith(Paths.DllSearchPaths);

                using (var assemblyPatcher = new AssemblyPatcher())
                {
                    assemblyPatcher.PatcherPlugins.Add(new PatcherPlugin
                    {
                        TargetDLLs = () => new[] { ConfigEntrypointAssembly.Value },
                        Patcher    = PatchEntrypoint,
                        TypeName   = "BepInEx.Chainloader"
                    });

                    assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                    Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} patcher plugin{(assemblyPatcher.PatcherPlugins.Count == 1 ? "" : "s")} loaded");

                    assemblyPatcher.LoadAssemblyDirectories(Paths.DllSearchPaths);

                    Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} assemblies discovered");

                    assemblyPatcher.PatchAndLoad();
                }


                Log.LogMessage("Preloader finished");

                Logger.Listeners.Remove(PreloaderLog);

                PreloaderLog.Dispose();
            }
            catch (Exception ex)
            {
                try
                {
                    Log.LogFatal("Could not run preloader!");
                    Log.LogFatal(ex);

                    if (!ConsoleManager.ConsoleActive)
                    {
                        //if we've already attached the console, then the log will already be written to the console
                        AllocateConsole();
                        Console.Write(PreloaderLog);
                    }
                }
                catch { }

                var log = string.Empty;

                try
                {
                    // We could use platform-dependent newlines, however the developers use Windows so this will be easier to read :)

                    log  = string.Join("\r\n", PreloaderConsoleListener.LogEvents.Select(x => x.ToString()).ToArray());
                    log += "\r\n";

                    PreloaderLog?.Dispose();
                    PreloaderLog = null;
                }
                catch { }

                File.WriteAllText(
                    Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"),
                    log + ex);
            }
        }
Esempio n. 10
0
        public static void ApplyInstructions(LaunchType launchType, List <PatchGroup> patchGroups, ProgressObject totalProgress)
        {
            //TODO: Use a different progress tracking system and make the entire patching operation more recoverable and fault-tolerant.
            //TODO: Refactor this method.
            AppInfo appInfo = AppContextManager.Context.Value;

            Assembly myAttributesAssembly     = typeof(AppInfo).Assembly;
            string   myAttributesAssemblyName = Path.GetFileName(myAttributesAssembly.Location);

            var fileProgress  = new ProgressObject();
            var patchProgress = new ProgressObject();

            totalProgress.Child.Value = fileProgress;
            fileProgress.Child.Value  = patchProgress;

            totalProgress.SetTaskData("Patching Game", appInfo.AppName, patchGroups.Count);

            foreach (PatchGroup patchGroup in patchGroups)
            {
                int patchCount = patchGroup.Instructions.Count;

                string destinationPath = patchGroup.TargetPath;

                var patcher = new AssemblyPatcher(destinationPath, Logger);
                patcher.EmbedHistory = true;

                string sourcePath = PatchingHelper.GetBackupForModified(destinationPath);
                string backupPath = PatchingHelper.GetBackupForOriginal(destinationPath);

                // note that Path.Combine(FILENAME, "..", OTHER_FILENAME) doesn't work on Mono but does work on .NET.
                string targetDirectory = Path.GetDirectoryName(destinationPath);

                string localAssemblyName = Path.Combine(targetDirectory, myAttributesAssemblyName);

                totalProgress.SetTaskData(string.Format("Patching {0}", appInfo.AppName), Path.GetFileName(destinationPath));

                fileProgress.SetTaskData("Patching File", total: 2 + patchCount, increment: true);
                fileProgress.SetTaskData(taskText: "Applying Patch");

                if (!PatchingHelper.DoesFileMatchPatchList(sourcePath, destinationPath, patchGroup.Instructions) || PreferencesManager.Preferences.AlwaysPatch)
                {
                    try
                    {
                        myAttributesAssembly.TryCopyAttributesAssembly(localAssemblyName);
                    }
                    catch (Exception exception)
                    {
                        Logger.Warning(exception, "Failed to read local attributes assembly so it will be overwritten.");
                    }

                    foreach (PatchInstruction patch in patchGroup.Instructions)
                    {
                        try
                        {
                            patcher.TryPatchManifest(patch, patchGroup, patchProgress);
                        }
                        catch (PatchingProcessException exception)
                        {
                            Logger.Show(exception);
                        }

                        fileProgress.SetTaskData(increment: true);
                    }

                    patchProgress.SetTaskData(string.Empty, string.Empty);

                    fileProgress.SetTaskData(taskText: "Writing Assembly", increment: true);

                    if (launchType == LaunchType.Test && Environment.OSVersion.Platform == PlatformID.Win32NT)
                    {
                        fileProgress.SetTaskData(taskText: "Running PEVerify");

                        string peOutput = patcher.TryRunPeVerify(appInfo, destinationPath);

                        Logger.Information(peOutput);
                    }

                    try
                    {
                        patcher.TryBackup(sourcePath, patchGroup);
                    }
                    catch (PatchingProcessException exception)
                    {
                        Logger.Show(exception);
                    }
                }
                else
                {
                    fileProgress.Current.Value += patchCount;
                }

                try
                {
                    LaunchManager.TrySwitchFilesSafely(sourcePath, destinationPath, backupPath, patchGroup);
                }
                catch (PatchingProcessException exception)
                {
                    Logger.Show(exception);
                }

                AssemblyCache.Default.ClearCache();

                totalProgress.SetTaskData(increment: true);
            }
        }
Esempio n. 11
0
    public static void Start(string[] args)
    {
        var preloaderListener = new PreloaderConsoleListener();

        Logger.Listeners.Add(preloaderListener);

        if (string.IsNullOrEmpty(ConfigEntrypointExecutable.Value))
        {
            Log.Log(LogLevel.Fatal,
                    $"Entry executable was not set. Please set this in your config before launching the application");
            Program.ReadExit();
            return;
        }

        var executablePath = Path.GetFullPath(ConfigEntrypointExecutable.Value);

        if (!File.Exists(executablePath))
        {
            Log.Log(LogLevel.Fatal, $"Unable to locate executable: {ConfigEntrypointExecutable.Value}");
            Program.ReadExit();
            return;
        }


        Paths.SetExecutablePath(executablePath);
        Program.ResolveDirectories.Add(Paths.GameRootPath);

        foreach (var searchDir in Program.ResolveDirectories)
        {
            TypeLoader.SearchDirectories.Add(searchDir);
        }

        if (PlatformHelper.Is(Platform.Windows))
        {
            AddDllDirectory(Paths.GameRootPath);
            SetDllDirectory(Paths.GameRootPath);
        }


        Logger.Sources.Add(TraceLogSource.CreateSource());

        ChainloaderLogHelper.PrintLogInfo(Log);

        Log.Log(LogLevel.Info, $"CLR runtime version: {Environment.Version}");


        AssemblyBuildInfo executableInfo, launcherInfo;

        using (var executableAssembly = AssemblyDefinition.ReadAssembly(executablePath))
            executableInfo = AssemblyBuildInfo.DetermineInfo(executableAssembly);

        using (var launcherAssembly = AssemblyDefinition.ReadAssembly(typeof(NetPreloader).Assembly.Location))
            launcherInfo = AssemblyBuildInfo.DetermineInfo(launcherAssembly);

        // we don't particularly care about AnyCPU here since the fallback bitness is almost never the case
        if (executableInfo.Is64Bit != launcherInfo.Is64Bit)
        {
            Log.LogError($"Game executable is {(executableInfo.Is64Bit ? "64" : "32")}-bit while BepInEx has been compiled as {(launcherInfo.Is64Bit ? "64" : "32")}-bit. Expect crashes");
        }

        if (executableInfo.NetFrameworkVersion != launcherInfo.NetFrameworkVersion || executableInfo.AssemblyFrameworkType != launcherInfo.AssemblyFrameworkType)
        {
            Log.LogWarning($"Game executable has been compiled as {executableInfo}, while BepInEx has been compiled as {launcherInfo}. There may be issues within the game caused by this");
        }

        Log.LogInfo($"Game executable build architecture: {executableInfo}");
        Log.LogInfo($"BepInEx launcher build architecture: {launcherInfo}");

        Log.Log(LogLevel.Message, "Preloader started");

        Assembly entrypointAssembly;

        using (var assemblyPatcher = new AssemblyPatcher())
        {
            assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

            Log.Log(LogLevel.Info,
                    $"{assemblyPatcher.PatcherContext.PatchDefinitions.Count} patcher definition(s) loaded");

            assemblyPatcher.LoadAssemblyDirectories(new[] { Paths.GameRootPath }, new[] { "dll", "exe" });

            Log.Log(LogLevel.Info, $"{assemblyPatcher.PatcherContext.AvailableAssemblies.Count} assemblies discovered");

            assemblyPatcher.PatchAndLoad();


            var assemblyName = AssemblyName.GetAssemblyName(executablePath);

            entrypointAssembly =
                assemblyPatcher.PatcherContext.LoadedAssemblies.Values.FirstOrDefault(x => x.FullName ==
                                                                                      assemblyName.FullName);

            foreach (var loadedAssembly in assemblyPatcher.PatcherContext.LoadedAssemblies)
            {
                // TODO: Need full paths for loaded assemblies
                var assemblyPath = Path.Combine(Paths.GameRootPath, loadedAssembly.Key);

                Log.LogDebug($"Registering '{assemblyPath}' as a loaded assembly");
                AssemblyFixes.AssemblyLocations[loadedAssembly.Value.FullName] = assemblyPath;
            }

            if (entrypointAssembly != null)
            {
                Log.LogDebug("Found patched entrypoint assembly! Using it");
            }
            else
            {
                Log.LogDebug("Using entrypoint assembly from disk");
                entrypointAssembly = Assembly.LoadFrom(executablePath);
            }
        }

        Log.LogMessage("Preloader finished");

        Logger.Listeners.Remove(preloaderListener);

        var chainloader = new NetChainloader();

        chainloader.Initialize();
        chainloader.Execute();


        AssemblyFixes.Execute(entrypointAssembly);

        try
        {
            var argList = new List <object>();

            var paramTypes = entrypointAssembly.EntryPoint.GetParameters();

            if (paramTypes.Length == 1 && paramTypes[0].ParameterType == typeof(string[]))
            {
                argList.Add(args);
            }
            else if (paramTypes.Length == 1 && paramTypes[0].ParameterType == typeof(string))
            {
                argList.Add(string.Join(" ", args));
            }
            else if (paramTypes.Length != 0)
            {
                // Only other entrypoint signatures I can think of that .NET supports is Task / Task<int>
                //   async entrypoints. That's a can of worms for another time though

                Log.LogFatal($"Could not figure out how to handle entrypoint method with this signature: {entrypointAssembly.EntryPoint.FullDescription()}");
                return;
            }

            entrypointAssembly.EntryPoint.Invoke(null, argList.ToArray());
        }
        catch (Exception ex)
        {
            Log.LogFatal($"Unhandled exception: {ex}");
        }
    }
Esempio n. 12
0
        public static int Main(string[] args)
        {
            bool interactive = true;

            if (args.Length > 0)
            {
                interactive = false;
            }

            foreach (string arg in args)
            {
                if (arg.Contains("--generatediffs"))
                {
                    gendiffs = true;
                }
            }

            newAssCS = true;

            Console.WriteLine(string.Format("[( Pluton Patcher v{0} )]", Version));
            try {
                plutonAssembly = AssemblyPatcher.FromFile("Pluton.dll");
                rustAssembly   = AssemblyPatcher.FromFile("Assembly-CSharp.dll");
            } catch (FileNotFoundException ex) {
                Console.WriteLine("You are missing " + ex.FileName + " did you move the patcher to the managed folder ?");
                if (interactive)
                {
                    Console.WriteLine("Press any key to continue...");
                }
                return((int)ExitCode.DLL_MISSING);
            } catch (Exception ex) {
                Console.WriteLine("An error occured while reading the assemblies :");
                Console.WriteLine(ex.ToString());
                if (interactive)
                {
                    Console.WriteLine("Press any key to continue...");
                }
                return((int)ExitCode.DLL_READ_ERROR);
            }

            bNPC        = rustAssembly.GetType("BaseNPC");
            bPlayer     = rustAssembly.GetType("BasePlayer");
            codeLock    = rustAssembly.GetType("CodeLock");
            hooksClass  = plutonAssembly.GetType("Pluton.Hooks");
            itemCrafter = rustAssembly.GetType("ItemCrafter");
            pLoot       = rustAssembly.GetType("PlayerLoot");

            //Check if patching is required
            TypePatcher plutonClass = rustAssembly.GetType("PlutonPatched");

            if (plutonClass == null)
            {
                try {
                    if (gendiffs)
                    {
                        string hash = string.Empty;
                        using (var sha512 = new System.Security.Cryptography.SHA512Managed())
                            hash = BitConverter.ToString(sha512.ComputeHash(File.ReadAllBytes("Assembly-CSharp.dll"))).Replace("-", "").ToLower();

                        Directory.CreateDirectory("diffs");

                        string hashpath = "diffs" + Path.DirectorySeparatorChar + "lastHash";

                        if (File.Exists(hashpath))
                        {
                            newAssCS = hash != File.ReadAllText(hashpath);
                        }

                        if (newAssCS)
                        {
                            foreach (var difffile in Directory.GetFiles("diffs"))
                            {
                                if (difffile.Contains(".htm"))
                                {
                                    string filename = Path.GetFileName(difffile);
                                    string dirname  = Path.GetDirectoryName(difffile);
                                    Directory.CreateDirectory(Path.Combine(dirname, "old"));
                                    File.Move(difffile, difffile.Replace(Path.Combine(dirname, filename), Path.Combine(dirname, "old", filename)));
                                }
                            }
                        }

                        if (gendiffs && newAssCS)
                        {
                            File.WriteAllText(hashpath, hash);
                        }
                    }
                    PatchASMCSharp();
                    Console.WriteLine("Patched Assembly-CSharp !");
                } catch (Exception ex) {
                    interactive = true;
                    Console.WriteLine("An error occured while patching Assembly-CSharp :");
                    Console.WriteLine();
                    Console.WriteLine(ex.Message.ToString());

                    //Normal handle for the others
                    Console.WriteLine();
                    Console.WriteLine(ex.StackTrace.ToString());
                    Console.WriteLine();

                    if (interactive)
                    {
                        Console.WriteLine("Press any key to continue...");
                    }
                    return((int)ExitCode.ACDLL_GENERIC_PATCH_ERR);
                }
            }
            else
            {
                Console.WriteLine("Assembly-CSharp.dll is already patched!");
                return((int)ExitCode.ACDLL_ALREADY_PATCHED);
            }

            try {
                rustAssembly.Write("Assembly-CSharp.dll");
            } catch (Exception ex) {
                Console.WriteLine("An error occured while writing the assembly :");
                Console.WriteLine("Error at: " + ex.TargetSite.Name);
                Console.WriteLine("Error msg: " + ex.Message);

                if (interactive)
                {
                    Console.WriteLine("Press any key to continue...");
                }

                return((int)ExitCode.DLL_WRITE_ERROR);
            }

            //Successfully patched the server
            Console.WriteLine("Completed !");

            if (interactive)
            {
                System.Threading.Thread.Sleep(250);
            }

            return((int)ExitCode.SUCCESS);
        }
Esempio n. 13
0
		private void ApplyInstructions(IEnumerable<PatchGroup> patchGroups, ProgressObject po) {
			//TODO: Use a different progress tracking system and make the entire patching operation more recoverable and fault-tolerant.
			//TODO: Refactor this method.
			patchGroups = patchGroups.ToList();
			var appInfo = AppInfo;
			var logger = Logger;
			var fileProgress = new ProgressObject();
			po.Child.Value = fileProgress;
			var patchProgress = new ProgressObject();
			fileProgress.Child.Value = patchProgress;
			var myAttributesAssembly = typeof (AppInfo).Assembly;
			var attributesAssemblyName = Path.GetFileName(myAttributesAssembly.Location);
			var history = new List<XmlFileHistory>();
			po.TaskTitle.Value = "Patching Game";
			po.TaskText.Value = appInfo.AppName;
			po.Total.Value = patchGroups.Count();

			foreach (var patchGroup in patchGroups) {
				var patchCount = patchGroup.Instructions.Count;
				po.TaskTitle.Value = $"Patching {appInfo.AppName}";
				var targetFile = patchGroup.TargetPath;
				po.TaskText.Value = Path.GetFileName(targetFile);
				//Note that Path.Combine(FILENAME, "..", OTHER_FILENAME) doesn't work on Mono but does work on .NET.
				var dir = Path.GetDirectoryName(targetFile);

				var localAssemblyName = Path.Combine(dir, attributesAssemblyName);
				var copy = true;
				fileProgress.TaskTitle.Value = "Patching File";
				fileProgress.Total.Value = 2 + patchCount;
				fileProgress.Current.Value++;

				var backupModified = PatchingHelper.GetBackupForModified(targetFile);
				var backupOrig = PatchingHelper.GetBackupForOriginal(targetFile);
				fileProgress.TaskText.Value = "Applying Patch";

				if (!PatchingHelper.DoesFileMatchPatchList(backupModified, targetFile, patchGroup.Instructions)
					|| Preferences.AlwaysPatch) {
					if (File.Exists(localAssemblyName)) {
						try {
							var localAssembly = AssemblyCache.Default.ReadAssembly(localAssemblyName);
							if (localAssembly.GetAssemblyMetadataString() == myAttributesAssembly.GetAssemblyMetadataString()) {
								copy = false;
							}
						}
						catch (Exception ex) {
							Logger.Warning(ex, $"Failed to read local attributes assembly so it will be overwritten.");
							//if reading the assembly failed for any reason, just ignore...
						}
					}
					if (copy) {
						File.Copy(myAttributesAssembly.Location, localAssemblyName, true);
					}

					var patcher = new AssemblyPatcher(targetFile, logger) {
						EmbedHistory = true
					};

					foreach (var patch in patchGroup.Instructions) {
						try {
							patcher.PatchManifest(patch.Patch, patchProgress.ToMonitor());
						}
						catch (PatchException ex) {
							throw new PatchingProcessException(ex) {
								AssociatedInstruction = patch,
								AssociatedPatchGroup = patchGroup,
								Step = PatchProcessingStep.ApplyingSpecificPatch
							};
						}
						fileProgress.Current.Value++;
					}
					patchProgress.TaskText.Value = "";
					patchProgress.TaskTitle.Value = "";


					fileProgress.Current.Value++;
					fileProgress.TaskText.Value = "Writing Assembly";
					if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
						fileProgress.TaskText.Value = "Running PEVerify...";
						var targetFolder = Path.GetDirectoryName(targetFile);
						try {
							var peOutput = patcher.RunPeVerify(new PEVerifyInput {
								AssemblyResolutionFolder = targetFolder,
								IgnoreErrors = AppInfo.IgnorePEVerifyErrors.ToList()
							});
							logger.Information(peOutput.Output);
						}
						catch (Exception ex) {
							logger.Error(ex, "Failed to run PEVerify on the assembly.");
						}
					}

					try {
						patcher.WriteTo(backupModified);
					}
					catch (Exception ex) {
						throw new PatchingProcessException(ex) {
							AssociatedInstruction = null,
							AssociatedPatchGroup = patchGroup,
							Step = PatchProcessingStep.WritingToFile
						};
					}
				} else {
					fileProgress.Current.Value += patchCount;
				}
				try {
					PatchingHelper.SwitchFilesSafely(backupModified, targetFile, backupOrig);
				}
				catch (Exception ex) {
					throw new PatchingProcessException(ex) {
						AssociatedInstruction = null,
						AssociatedPatchGroup = patchGroup,
						Step = PatchProcessingStep.PerformingSwitch
					};
				}
				AssemblyCache.Default.ClearCache();
				po.Current.Value++;
			}
		}
Esempio n. 14
0
        public static void Start(string[] args)
        {
            if (string.IsNullOrEmpty(ConfigEntrypointExecutable.Value))
            {
                Log.LogFatal($"Entry executable was not set. Please set this in your config before launching the application");
                Program.ReadExit();
                return;
            }

            string executablePath = Path.GetFullPath(ConfigEntrypointExecutable.Value);

            if (!File.Exists(executablePath))
            {
                Log.LogFatal($"Unable to locate executable: {ConfigEntrypointExecutable.Value}");
                Program.ReadExit();
                return;
            }

            Paths.SetExecutablePath(executablePath);
            Program.ResolveDirectories.Add(Paths.GameRootPath);
            TypeLoader.SearchDirectories.Add(Paths.GameRootPath);

            Logger.Sources.Add(TraceLogSource.CreateSource());

            ChainloaderLogHelper.PrintLogInfo(Log);

            Log.LogInfo($"CLR runtime version: {Environment.Version}");

            Log.LogMessage("Preloader started");

            Assembly entrypointAssembly;

            using (var assemblyPatcher = new AssemblyPatcher())
            {
                assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");

                assemblyPatcher.LoadAssemblyDirectory(Paths.GameRootPath, "dll", "exe");

                Log.LogInfo($"{assemblyPatcher.AssembliesToPatch.Count} assemblies discovered");

                assemblyPatcher.PatchAndLoad();


                var assemblyName = AssemblyName.GetAssemblyName(executablePath);

                entrypointAssembly = assemblyPatcher.LoadedAssemblies.Values.FirstOrDefault(x => x.FullName == assemblyName.FullName);

                if (entrypointAssembly != null)
                {
                    Log.LogDebug("Found patched entrypoint assembly! Using it");
                }
                else
                {
                    Log.LogDebug("Using entrypoint assembly from disk");
                    entrypointAssembly = Assembly.LoadFrom(executablePath);
                }
            }

            Log.LogMessage("Preloader finished");

            var chainloader = new NetChainloader();

            chainloader.Initialize();
            chainloader.Execute();


            AssemblyFix.Execute(entrypointAssembly);

            entrypointAssembly.EntryPoint.Invoke(null, new [] { args });
        }
Esempio n. 15
0
    public static void Run()
    {
        try
        {
            HarmonyBackendFix.Initialize();

            ConsoleManager.Initialize(false, false);

            PreloaderLog = new PreloaderConsoleListener();
            Logger.Listeners.Add(PreloaderLog);

            if (ConsoleManager.ConsoleEnabled)
            {
                ConsoleManager.CreateConsole();
                Logger.Listeners.Add(new ConsoleLogListener());
            }

            ChainloaderLogHelper.PrintLogInfo(Log);

            Log.Log(LogLevel.Debug, $"Game executable path: {Paths.ExecutablePath}");
            Log.Log(LogLevel.Debug, $"Unhollowed assembly directory: {IL2CPPUnhollowedPath}");
            Log.Log(LogLevel.Debug, $"BepInEx root path: {Paths.BepInExRootPath}");

            UnhollowerLog              = Logger.CreateLogSource("Unhollower");
            LogSupport.InfoHandler    += UnhollowerLog.LogInfo;
            LogSupport.WarningHandler += UnhollowerLog.LogWarning;
            LogSupport.TraceHandler   += UnhollowerLog.LogDebug;
            LogSupport.ErrorHandler   += UnhollowerLog.LogError;

            InitializeUnityVersion();

            if (ProxyAssemblyGenerator.CheckIfGenerationRequired())
            {
                ProxyAssemblyGenerator.GenerateAssemblies();
            }

            UnityVersionHandler.Initialize(UnityVersion.Major, UnityVersion.Minor, UnityVersion.Build);

            using (var assemblyPatcher = new AssemblyPatcher())
            {
                assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                Log.LogInfo($"{assemblyPatcher.PatcherContext.PatcherPlugins.Count} patcher plugin{(assemblyPatcher.PatcherContext.PatcherPlugins.Count == 1 ? "" : "s")} loaded");

                assemblyPatcher.LoadAssemblyDirectories(IL2CPPUnhollowedPath);

                Log.LogInfo($"{assemblyPatcher.PatcherContext.PatcherPlugins.Count} assemblies discovered");

                assemblyPatcher.PatchAndLoad();
            }


            Logger.Listeners.Remove(PreloaderLog);


            Chainloader = new IL2CPPChainloader();

            Chainloader.Initialize();
        }
        catch (Exception ex)
        {
            Log.Log(LogLevel.Fatal, ex);

            throw;
        }
    }