Пример #1
0
 private static int Exit(string msg = "")
 {
     XConsole.WriteLine(msg + "\n" + XConsole.Info("Exited."));
     Console.ReadKey(true);
     return(1);
 }
Пример #2
0
        public static int Main(string[] args)
        {
            // Console.ReadKey(true);

            if (args.Length < 2)
            {
                return(Exit("osu!patch - osu! assembly patcher based on NameMapper\n" +
                            "by exys, 2019 - 2020\n" +
                            "modded by Aoba Suzukaze, 2020\n" +
                            "\n" +
                            "Usage:\n" +
                            "osu!patch [clean module] [obfuscated module]"));
            }

            if (!File.Exists(_cleanOsuPath = Path.GetFullPath(args[0])))
            {
                return(XConsole.PrintFatal("Specified clean module path does not exist!\n"));
            }

            if (!File.Exists(_obfOsuPath = Path.GetFullPath(args[1])))
            {
                return(XConsole.PrintFatal("Specified obfuscated module path does not exist!\n"));
            }

            try
            {
                _obfOsuModule   = ModuleDefMD.Load(_obfOsuPath);
                _cleanOsuModule = ModuleDefMD.Load(_cleanOsuPath);

                _obfOsuAssembly = Assembly.LoadFile(_obfOsuPath);
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Unable to load one of the modules! Details:\n" + ex)); }

            ObfOsuHash = MD5Helper.Compute(_obfOsuPath);             // ORIGINAL!!!!!!! hash, PLEASE PASS UNMODIFIED PEPPY-SIGNED ASSEMBLY AS _obfOsuModule!@!!32R1234 (refer to "Patch on update" patch)

            XConsole.PrintInfo($"Loaded assemblies: {_cleanOsuModule.Assembly.FullName} (clean); {_obfOsuModule.Assembly.FullName} (obfuscated).");
            XConsole.PrintInfo("MD5 hash of obfuscated assembly: " + ObfOsuHash);

            try
            {
                LoadPlugins();                 // Loading plugins
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Something really bad happened while trying to process plugins! Details:\n" + ex)); }

            try
            {
                XConsole.PrintInfo("Cleaning control flow of obfuscated assembly");
                CleanControlFlow();
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Unable to deobfuscate control flow of obfuscated assembly! Details:\n" + ex)); }

            try
            {
                XConsole.PrintInfo("Fixing strings in obfuscated assembly.");
                StringFixer.Fix(_obfOsuModule, _obfOsuAssembly);                 // Fixing strings
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Unable to fix strings of obfuscated assembly! Details:\n" + ex)); }

            if (!Directory.Exists(CacheFolderLocation))
            {
                XConsole.PrintInfo("Creating cache folder...");
                Directory.CreateDirectory(CacheFolderLocation);
            }

            try
            {
                var nameProvider = InitializeNameProvider();                 // Fixing names (SimpleNameProvider/MapperNameProvider)
                _obfOsuExplorer = new ModuleExplorer(_obfOsuModule, nameProvider);
            }
            catch (Exception ex) { return(XConsole.PrintFatal("Unable to get clean names for obfuscated assembly! Details:\n" + ex)); }

#if DEBUG
            _obfOsuModule.Write(Path.Combine(Path.GetDirectoryName(_obfOsuPath), "OsuObfModule-cflow-string-nmapped.exe"), new ModuleWriterOptions(_obfOsuModule)
            {
                MetadataOptions = { Flags = DEFAULT_METADATA_FLAGS }
            });
#endif

            XConsole.PrintInfo("Done! Now patching.");

            bool overallSuccess = true;

            var failedDetails = new List <PatchResult>();

            void ExecutePatchCli(Patch patch)
            {
                XConsole.PrintInfo($"{patch.Name}: ", false);

                if (File.Exists(ConfigFileLocation))                 // incase if config file not initialized
                {
                    patch.Enabled = GetConfigEnabled(patch.Name);
                }

                PatchResult res = patch.Execute(_obfOsuExplorer);

                switch (res.Result)
                {
                case PatchStatus.Disabled:
                    Console.ForegroundColor = ConsoleColor.Gray;
                    XConsole.WriteLine("DISABLED");
                    break;

                case PatchStatus.Exception:
                case PatchStatus.Failure:
                    Console.ForegroundColor = ConsoleColor.Red;
                    XConsole.WriteLine("FAIL");
                    failedDetails.Add(res);
                    overallSuccess = false;
                    break;

                case PatchStatus.Success:
                    Console.ForegroundColor = ConsoleColor.Green;
                    XConsole.WriteLine("DONE");
                    break;

                default:
                    Console.ForegroundColor = ConsoleColor.DarkGray;
                    XConsole.WriteLine("[???]");
                    break;
                }

                Console.ResetColor();
            }

            // Executing local patches.
            foreach (var patch in LocalPatches.PatchList)
            {
                ExecutePatchCli(patch);
            }

            XConsole.PrintInfo("Done processing all local patches! Now processing patches from loaded add-ons...");

#if !CORE_PATCHES_ONLY
            // Executing all patches from all loaded plugins from all loaded assemblies (what a hierarchy)
            foreach (var plugin in _loadedPlugins)
            {
                XConsole.PrintInfo($"{plugin.AssemblyName}: Processing plugin: {plugin.TypeName}.");

                foreach (var patch in plugin.Type.GetPatches())
                {
                    ExecutePatchCli(patch);
                }

                XConsole.PrintInfo($"{plugin.AssemblyName}: Done processing: {plugin.TypeName}.");
            }
#endif
            if (!File.Exists(ConfigFileLocation))
            {
                XConsole.PrintInfo("Creating config file...");
                var configLines = string.Empty;

                foreach (var patch in Patches)
                {
                    configLines += patch.Name + " = " + "Enabled\n";                     // probably bad implementation of config but simplest i can imagine
                }
                File.WriteAllText(ConfigFileLocation, configLines);
                XConsole.PrintInfo("Config file created!");
            }

            XConsole.PrintInfo("Done processing all plugins.");

            if (failedDetails.Any())
            {
                XConsole.PrintInfo("There's some details about failed patches.");

                foreach (var details in failedDetails)
                {
                    details.PrintDetails(Console.Out);
                    XConsole.WriteLine();
                }
            }

            if (!overallSuccess)
            {
                XConsole.PrintInfo("There are some failed patches. Do you want to continue?");
                XConsole.PrintWarn("In case of self-update pressing 'N' will leave stock version of osu! without patching it!");
                XConsole.Write(XConsole.PAD + "Continue? (y/n) ");

                var exit = false;

                while (true)
                {
                    var key = Console.ReadKey(true).Key;

                    if (key == ConsoleKey.Y)
                    {
                        break;
                    }

                    if (key == ConsoleKey.N)
                    {
                        exit = true;
                        break;
                    }
                }

                XConsole.WriteLine();

                if (exit)
                {
                    return(Exit(XConsole.Info("Aborted by user.")));
                }
            }

            //string filename = Path.GetFileNameWithoutExtension(_obfOsuPath) + "-osupatch" + Path.GetExtension(_obfOsuPath);
            string filename = "ainu.exe";

            XConsole.PrintInfo($"Saving assembly as {filename}");

            try
            {
                _obfOsuModule.Write(Path.Combine(Path.GetDirectoryName(_obfOsuPath), filename), new ModuleWriterOptions(_obfOsuModule)
                {
                    MetadataOptions = { Flags = DEFAULT_METADATA_FLAGS }
                });
            }
            catch (Exception ex) { return(Exit(XConsole.Fatal("Unable to save patched assembly! Details:\n" + ex))); }

            _cleanOsuModule.Dispose();
            _obfOsuModule.Dispose();

#if DEBUG
            Console.ReadKey(true);
#endif

#if LIVE_DEBUG
            Process.Start(new ProcessStartInfo
            {
                FileName         = "cmd",
                Arguments        = "/c timeout /T 1 /NOBREAK & move /Y \"osu!-osupatch.exe\" \"osu!.exe\"",
                WorkingDirectory = Environment.CurrentDirectory,
                WindowStyle      = ProcessWindowStyle.Hidden,
                CreateNoWindow   = true,
                UseShellExecute  = false
            });
#endif

            return(overallSuccess ? 0 : 1);
        }